@agentprojectcontext/apx 1.39.1 → 1.40.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/package.json +1 -1
- package/src/core/agent/constants.js +7 -1
- package/src/core/agent/retry.js +9 -0
- package/src/core/agent/run-agent.js +56 -5
- package/src/core/agent/tools/pseudo-tools.js +13 -1
- package/src/core/channels/telegram/dispatch.js +23 -3
- package/src/core/engines/mock.js +33 -10
- package/src/core/i18n/en.js +2 -4
- package/src/core/i18n/es.js +1 -4
- package/src/core/i18n/index.js +5 -1
- package/src/core/i18n/pt.js +1 -3
- package/src/core/routines/runner.js +15 -3
- package/src/host/daemon/api/admin.js +29 -0
- package/src/interfaces/web/dist/assets/index-Cg-uHCex.js +646 -0
- package/src/interfaces/web/dist/assets/index-Cg-uHCex.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-wrEbTJbc.css +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/src/App.tsx +22 -11
- package/src/interfaces/web/src/components/AddProjectDialog.tsx +66 -34
- package/src/interfaces/web/src/components/ModelCombobox.tsx +6 -3
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +28 -25
- package/src/interfaces/web/src/components/chat/ModelPicker.tsx +19 -17
- package/src/interfaces/web/src/components/deck/WidgetRow.tsx +9 -7
- package/src/interfaces/web/src/components/inputs/VarTokenInput.tsx +21 -19
- package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +3 -2
- package/src/interfaces/web/src/components/routines/AvailableVarsCard.tsx +23 -0
- package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +189 -0
- package/src/interfaces/web/src/components/routines/ReadOnlyBlock.tsx +14 -0
- package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +86 -0
- package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +263 -0
- package/src/interfaces/web/src/components/routines/RoutineList.tsx +59 -0
- package/src/interfaces/web/src/components/routines/VarTextarea.tsx +70 -0
- package/src/interfaces/web/src/components/routines/shared.ts +89 -0
- package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +19 -16
- package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +10 -8
- package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +7 -4
- package/src/interfaces/web/src/components/ui/chat-input.tsx +24 -21
- package/src/interfaces/web/src/components/ui/sidebar.tsx +20 -18
- package/src/interfaces/web/src/components/ui.tsx +4 -0
- package/src/interfaces/web/src/i18n/en.ts +34 -11
- package/src/interfaces/web/src/i18n/es.ts +34 -11
- package/src/interfaces/web/src/lib/api/filesystem.ts +6 -0
- package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +11 -3
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +6 -3
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +8 -5
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +16 -9
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +126 -373
- package/src/interfaces/web/src/styles.css +5 -0
- package/src/interfaces/web/dist/assets/index-CAKEYko0.css +0 -1
- package/src/interfaces/web/dist/assets/index-UzqHxD0B.js +0 -639
- package/src/interfaces/web/dist/assets/index-UzqHxD0B.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { Braces, Loader2, RefreshCw } from "lucide-react";
|
|
3
3
|
import { Button, Dialog, Field, Input, Switch, Textarea } from "../../ui";
|
|
4
|
+
import { Tip } from "../../ui/tip";
|
|
4
5
|
import { UiSelect } from "../../UiSelect";
|
|
5
6
|
import { ModelCombobox } from "../../ModelCombobox";
|
|
6
7
|
import { Engines } from "../../../lib/api";
|
|
@@ -363,10 +364,12 @@ export function ProviderModal({ open, initial, existingSlugs, onClose, onSave }:
|
|
|
363
364
|
options={modelOptions}
|
|
364
365
|
className="flex-1"
|
|
365
366
|
/>
|
|
366
|
-
<
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
<Tip content={t("providers_modal.list_models_hint")}>
|
|
368
|
+
<Button size="sm" variant="secondary" onClick={loadModels} disabled={loadingModels} aria-label={t("providers_modal.list_models_hint")}>
|
|
369
|
+
{loadingModels ? <Loader2 className="size-3.5 animate-spin" /> : <RefreshCw className="size-3.5" />}
|
|
370
|
+
{t("providers_modal.load_models")}
|
|
371
|
+
</Button>
|
|
372
|
+
</Tip>
|
|
370
373
|
</div>
|
|
371
374
|
{modelError && <p className="text-[11px] text-amber-400">{modelError}</p>}
|
|
372
375
|
</div>
|
|
@@ -5,6 +5,7 @@ import { ArrowUp, Square } from "lucide-react"
|
|
|
5
5
|
|
|
6
6
|
import { cn } from "@/lib/utils"
|
|
7
7
|
import { Button } from "@/components/ui/button"
|
|
8
|
+
import { Tip } from "./tip"
|
|
8
9
|
import { t } from "@/i18n"
|
|
9
10
|
|
|
10
11
|
interface ChatInputProps {
|
|
@@ -105,28 +106,30 @@ export function ChatInput({
|
|
|
105
106
|
{footer}
|
|
106
107
|
</div>
|
|
107
108
|
{busy && onStop ? (
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
<Tip content={t("chat_ui.stop")}>
|
|
110
|
+
<Button
|
|
111
|
+
type="button"
|
|
112
|
+
size="icon-sm"
|
|
113
|
+
variant="destructive"
|
|
114
|
+
onClick={onStop}
|
|
115
|
+
aria-label={t("chat_ui.stop")}
|
|
116
|
+
>
|
|
117
|
+
<Square className="size-3.5" fill="currentColor" />
|
|
118
|
+
</Button>
|
|
119
|
+
</Tip>
|
|
118
120
|
) : (
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
<Tip content={t("chat_ui.send")}>
|
|
122
|
+
<Button
|
|
123
|
+
type="button"
|
|
124
|
+
size="icon-sm"
|
|
125
|
+
variant="default"
|
|
126
|
+
onClick={onSubmit}
|
|
127
|
+
disabled={!canSend}
|
|
128
|
+
aria-label={t("chat_ui.send")}
|
|
129
|
+
>
|
|
130
|
+
<ArrowUp className="size-4" />
|
|
131
|
+
</Button>
|
|
132
|
+
</Tip>
|
|
130
133
|
)}
|
|
131
134
|
</div>
|
|
132
135
|
</div>
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
SheetTitle,
|
|
20
20
|
} from "@/components/ui/sheet"
|
|
21
21
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
22
|
+
import { Tip } from "./tip"
|
|
22
23
|
import {
|
|
23
24
|
Tooltip,
|
|
24
25
|
TooltipContent,
|
|
@@ -282,24 +283,25 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
|
|
|
282
283
|
const { toggleSidebar } = useSidebar()
|
|
283
284
|
|
|
284
285
|
return (
|
|
285
|
-
<
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
286
|
+
<Tip content={t("sidebar_ui.toggle")}>
|
|
287
|
+
<button
|
|
288
|
+
data-sidebar="rail"
|
|
289
|
+
data-slot="sidebar-rail"
|
|
290
|
+
aria-label={t("sidebar_ui.toggle")}
|
|
291
|
+
tabIndex={-1}
|
|
292
|
+
onClick={toggleSidebar}
|
|
293
|
+
className={cn(
|
|
294
|
+
"absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2",
|
|
295
|
+
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
|
|
296
|
+
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
|
297
|
+
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
|
|
298
|
+
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
|
|
299
|
+
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
|
|
300
|
+
className
|
|
301
|
+
)}
|
|
302
|
+
{...props}
|
|
303
|
+
/>
|
|
304
|
+
</Tip>
|
|
303
305
|
)
|
|
304
306
|
}
|
|
305
307
|
|
|
@@ -12,6 +12,10 @@ import { Switch as SSwitch } from "./ui/switch";
|
|
|
12
12
|
import { Spinner as SSpinner } from "./ui/spinner";
|
|
13
13
|
import { Dialog as DialogRoot, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog";
|
|
14
14
|
|
|
15
|
+
// Re-export the tooltip convenience wrapper so call sites can grab it from the
|
|
16
|
+
// same barrel as Button/Field/etc.: `import { Button, Tip } from "../ui"`.
|
|
17
|
+
export { Tip } from "./ui/tip";
|
|
18
|
+
|
|
15
19
|
// ── Button ──────────────────────────────────────────────────────────────────
|
|
16
20
|
type Variant = "primary" | "secondary" | "ghost" | "destructive";
|
|
17
21
|
type Size = "sm" | "md";
|
|
@@ -128,6 +128,7 @@ export const en = {
|
|
|
128
128
|
path_required: "Path required.",
|
|
129
129
|
registered: "Project #{id} registered.",
|
|
130
130
|
search_btn: "Browse",
|
|
131
|
+
picker_prompt: "Pick the project folder",
|
|
131
132
|
browser_unavailable: "Browser unavailable until daemon restarts. Paste path manually.",
|
|
132
133
|
no_folders: "No folders.",
|
|
133
134
|
},
|
|
@@ -368,6 +369,7 @@ export const en = {
|
|
|
368
369
|
new: "new",
|
|
369
370
|
new_btn: "New",
|
|
370
371
|
delete_confirm: "Delete routine {name}?",
|
|
372
|
+
delete_confirm_body: "This can't be undone.",
|
|
371
373
|
saved: "Routine saved.",
|
|
372
374
|
paused: "paused",
|
|
373
375
|
next_run: "next:",
|
|
@@ -385,6 +387,24 @@ export const en = {
|
|
|
385
387
|
schedule_hint: "Choose a preset or type manually. Manual = only runs via Run button.",
|
|
386
388
|
vars_title: "Available variables",
|
|
387
389
|
what_happens: "What will happen",
|
|
390
|
+
list_title: "Routines",
|
|
391
|
+
detail_empty: "Pick a routine from the list.",
|
|
392
|
+
edit_btn: "Edit",
|
|
393
|
+
edit_hint: "Open the editor: kind, schedule, prompt, pre/post and variables.",
|
|
394
|
+
block_pre: "Pre-commands",
|
|
395
|
+
block_post: "Post-commands",
|
|
396
|
+
block_prompt: "Prompt",
|
|
397
|
+
block_text: "Text",
|
|
398
|
+
block_command: "Command",
|
|
399
|
+
block_empty: "(empty)",
|
|
400
|
+
runs_title: "Executions",
|
|
401
|
+
runs_empty: "No executions yet.",
|
|
402
|
+
runs_close: "Close",
|
|
403
|
+
runs_no_detail: "No further detail.",
|
|
404
|
+
runs_output: "Output",
|
|
405
|
+
status_ok: "ok",
|
|
406
|
+
status_error: "error",
|
|
407
|
+
status_skipped: "skipped",
|
|
388
408
|
agent_field: "Agent (spec.agent)",
|
|
389
409
|
agent_hint: "Who executes the routine.",
|
|
390
410
|
agent_loading: "loading…",
|
|
@@ -399,7 +419,7 @@ export const en = {
|
|
|
399
419
|
post_hint: "Shell AFTER the prompt. One per line.",
|
|
400
420
|
tg_channel: "Channel (spec.channel)",
|
|
401
421
|
tg_chat_id: "Chat ID (spec.chat_id)",
|
|
402
|
-
tg_text: "
|
|
422
|
+
tg_text: "Telegram Message (spec.text)",
|
|
403
423
|
tg_text_hint: "Fixed message to send. Does not use a model.",
|
|
404
424
|
shell_field: "Command (spec.command)",
|
|
405
425
|
shell_hint: "Runs as-is in the shell. No prompt, no pre/post.",
|
|
@@ -411,13 +431,16 @@ export const en = {
|
|
|
411
431
|
toggle_error: "toggle failed",
|
|
412
432
|
delete_error: "delete failed",
|
|
413
433
|
run_success: "{name} fired.",
|
|
434
|
+
run_confirm: "Run routine {name} now?",
|
|
435
|
+
run_confirm_body: "Runs the action once, regardless of the schedule.",
|
|
436
|
+
running: "Running…",
|
|
414
437
|
delete_success: "deleted.",
|
|
415
438
|
},
|
|
416
439
|
|
|
417
440
|
agents: {
|
|
418
441
|
title: "Agents",
|
|
419
|
-
subtitle: "Defined in
|
|
420
|
-
subtitle_full: "Defined in
|
|
442
|
+
subtitle: "Defined in .apc/agents/<slug>.md.",
|
|
443
|
+
subtitle_full: "Defined in .apc/agents/<slug>.md. Runtime memory lives under ~/.apx/projects/<id>/agents/<slug>/.",
|
|
421
444
|
empty: "No agents. Add one with <code>apx agent add</code> or the button.",
|
|
422
445
|
empty_text: "No agents. Add one with `apx agent add` or the button above.",
|
|
423
446
|
new: "Agent",
|
|
@@ -1243,14 +1266,14 @@ export const en = {
|
|
|
1243
1266
|
preset_daily_9am: "daily 9am",
|
|
1244
1267
|
preset_weekdays_9am: "weekdays 9am",
|
|
1245
1268
|
preset_manual: "Manual",
|
|
1246
|
-
var_pre_output_prompt: "
|
|
1247
|
-
var_llm_output: "
|
|
1248
|
-
var_status: "ok
|
|
1249
|
-
var_skipped: "1 if the action was skipped.",
|
|
1250
|
-
var_pre_output: "
|
|
1251
|
-
var_pre_output_file: "
|
|
1252
|
-
var_pre_exit: "Exit code of the pre-commands.",
|
|
1253
|
-
var_routine: "Name of
|
|
1269
|
+
var_pre_output_prompt: "Text output of the pre-commands. Replaced inside the prompt/text before it is sent. Use it to inject fresh data (weather, an API) into the instruction.",
|
|
1270
|
+
var_llm_output: "Final answer from the agent or super-agent. Available in the post-commands as an env var — e.g. forward it via Telegram.",
|
|
1271
|
+
var_status: "Action result: ok or error. Available in the post-commands to branch on what happened.",
|
|
1272
|
+
var_skipped: "1 if the action was skipped (via skip_prompt_on), 0 if it ran. Available in the post-commands.",
|
|
1273
|
+
var_pre_output: "Full pre-commands output, as an env var in the post-commands (up to 32k).",
|
|
1274
|
+
var_pre_output_file: "Path to a temp file with the pre-commands output. For large outputs not suited to an env var.",
|
|
1275
|
+
var_pre_exit: "Exit code of the last pre-command (0 = ok). Available in the post-commands.",
|
|
1276
|
+
var_routine: "Name of this routine. Available as an env var in the commands.",
|
|
1254
1277
|
summary_runs_agent: "Runs the agent \"{agent}\"",
|
|
1255
1278
|
summary_runs_agent_none: "Runs an agent (none chosen yet)",
|
|
1256
1279
|
summary_super_agent: "Calls the super-agent",
|
|
@@ -129,6 +129,7 @@ export const es = {
|
|
|
129
129
|
path_required: "Ruta requerida.",
|
|
130
130
|
registered: "Proyecto #{id} registrado.",
|
|
131
131
|
search_btn: "Buscar",
|
|
132
|
+
picker_prompt: "Elegí la carpeta del proyecto",
|
|
132
133
|
browser_unavailable: "Explorador no disponible hasta reiniciar daemon. Pegá ruta manual.",
|
|
133
134
|
no_folders: "Sin carpetas.",
|
|
134
135
|
},
|
|
@@ -369,6 +370,7 @@ export const es = {
|
|
|
369
370
|
new: "nueva",
|
|
370
371
|
new_btn: "Nueva",
|
|
371
372
|
delete_confirm: "Borrar rutina {name}?",
|
|
373
|
+
delete_confirm_body: "Esta acción no se puede deshacer.",
|
|
372
374
|
saved: "Rutina guardada.",
|
|
373
375
|
paused: "pausada",
|
|
374
376
|
next_run: "próxima:",
|
|
@@ -386,6 +388,24 @@ export const es = {
|
|
|
386
388
|
schedule_hint: "Elegí un preset o escribilo a mano. Manual = solo corre con el botón Run.",
|
|
387
389
|
vars_title: "Variables disponibles",
|
|
388
390
|
what_happens: "Qué va a pasar",
|
|
391
|
+
list_title: "Rutinas",
|
|
392
|
+
detail_empty: "Elegí una rutina de la lista.",
|
|
393
|
+
edit_btn: "Editar",
|
|
394
|
+
edit_hint: "Abrir el editor: tipo, intervalo, prompt, pre/post y variables.",
|
|
395
|
+
block_pre: "Pre-commands",
|
|
396
|
+
block_post: "Post-commands",
|
|
397
|
+
block_prompt: "Prompt",
|
|
398
|
+
block_text: "Texto",
|
|
399
|
+
block_command: "Comando",
|
|
400
|
+
block_empty: "(vacío)",
|
|
401
|
+
runs_title: "Ejecuciones",
|
|
402
|
+
runs_empty: "Sin ejecuciones todavía.",
|
|
403
|
+
runs_close: "Cerrar",
|
|
404
|
+
runs_no_detail: "Sin más detalle.",
|
|
405
|
+
runs_output: "Salida",
|
|
406
|
+
status_ok: "ok",
|
|
407
|
+
status_error: "error",
|
|
408
|
+
status_skipped: "salteada",
|
|
389
409
|
agent_field: "Agente (spec.agent)",
|
|
390
410
|
agent_hint: "Quién ejecuta la rutina.",
|
|
391
411
|
agent_loading: "cargando…",
|
|
@@ -400,7 +420,7 @@ export const es = {
|
|
|
400
420
|
post_hint: "Shell DESPUÉS del prompt. Uno por línea.",
|
|
401
421
|
tg_channel: "Canal (spec.channel)",
|
|
402
422
|
tg_chat_id: "Chat ID (spec.chat_id)",
|
|
403
|
-
tg_text: "
|
|
423
|
+
tg_text: "Mensaje de Telegram (spec.text)",
|
|
404
424
|
tg_text_hint: "Mensaje fijo a enviar. No usa modelo.",
|
|
405
425
|
shell_field: "Comando (spec.command)",
|
|
406
426
|
shell_hint: "Corre tal cual en el shell. Sin prompt ni pre/post.",
|
|
@@ -412,13 +432,16 @@ export const es = {
|
|
|
412
432
|
toggle_error: "toggle falló",
|
|
413
433
|
delete_error: "delete falló",
|
|
414
434
|
run_success: "{name} disparada.",
|
|
435
|
+
run_confirm: "¿Ejecutar la rutina {name} ahora?",
|
|
436
|
+
run_confirm_body: "Corre la acción una vez, sin esperar al horario.",
|
|
437
|
+
running: "Ejecutando…",
|
|
415
438
|
delete_success: "borrada.",
|
|
416
439
|
},
|
|
417
440
|
|
|
418
441
|
agents: {
|
|
419
442
|
title: "Agents",
|
|
420
|
-
subtitle: "Definidos en
|
|
421
|
-
subtitle_full: "Definidos en
|
|
443
|
+
subtitle: "Definidos en .apc/agents/<slug>.md.",
|
|
444
|
+
subtitle_full: "Definidos en .apc/agents/<slug>.md. La memoria runtime vive en ~/.apx/projects/<id>/agents/<slug>/.",
|
|
422
445
|
empty: "Sin agents. Agregá uno con <code>apx agent add</code> o el botón.",
|
|
423
446
|
empty_text: "Sin agents. Agregá uno con `apx agent add` o el botón de arriba.",
|
|
424
447
|
new: "Agente",
|
|
@@ -1241,14 +1264,14 @@ export const es = {
|
|
|
1241
1264
|
preset_daily_9am: "diario 9am",
|
|
1242
1265
|
preset_weekdays_9am: "días hábiles 9am",
|
|
1243
1266
|
preset_manual: "Manual",
|
|
1244
|
-
var_pre_output_prompt: "Salida de los pre-commands,
|
|
1245
|
-
var_llm_output: "Respuesta del agente
|
|
1246
|
-
var_status: "ok
|
|
1247
|
-
var_skipped: "1 si la acción se
|
|
1248
|
-
var_pre_output: "Salida de los pre-commands.",
|
|
1249
|
-
var_pre_output_file: "
|
|
1250
|
-
var_pre_exit: "Código de salida
|
|
1251
|
-
var_routine: "Nombre de
|
|
1267
|
+
var_pre_output_prompt: "Salida de texto de los pre-commands. Se reemplaza dentro del prompt/texto antes de enviarlo. Útil para inyectar datos frescos (clima, una API) en la instrucción.",
|
|
1268
|
+
var_llm_output: "Respuesta final del agente o super-agente. Disponible en los post-commands como variable de entorno. Ej: reenviarla por Telegram.",
|
|
1269
|
+
var_status: "Resultado de la acción: ok o error. Disponible en los post-commands para decidir qué hacer después.",
|
|
1270
|
+
var_skipped: "Vale 1 si la acción se salteó (por skip_prompt_on), 0 si corrió. Disponible en los post-commands.",
|
|
1271
|
+
var_pre_output: "Salida completa de los pre-commands, como variable de entorno en los post-commands (hasta 32k).",
|
|
1272
|
+
var_pre_output_file: "Ruta a un archivo temporal con la salida de los pre-commands. Para salidas grandes que no convienen como variable.",
|
|
1273
|
+
var_pre_exit: "Código de salida del último pre-command (0 = ok). Disponible en los post-commands.",
|
|
1274
|
+
var_routine: "Nombre de esta rutina. Disponible como variable de entorno en los comandos.",
|
|
1252
1275
|
summary_runs_agent: "Corre el agente \"{agent}\"",
|
|
1253
1276
|
summary_runs_agent_none: "Corre un agente (todavía no elegiste cuál)",
|
|
1254
1277
|
summary_super_agent: "Llama al super-agente",
|
|
@@ -6,7 +6,13 @@ export interface DirectoryList {
|
|
|
6
6
|
entries: string[];
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export type PickDirResult = { path: string } | { cancelled: true };
|
|
10
|
+
|
|
9
11
|
export const Filesystem = {
|
|
10
12
|
dirs: (path: string) =>
|
|
11
13
|
http.get<DirectoryList>(`/admin/fs/dirs?path=${encodeURIComponent(path)}`),
|
|
14
|
+
pickDir: (prompt?: string) =>
|
|
15
|
+
http.get<PickDirResult>(
|
|
16
|
+
`/admin/fs/pick-dir${prompt ? `?prompt=${encodeURIComponent(prompt)}` : ""}`,
|
|
17
|
+
),
|
|
12
18
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { useNavigate } from "react-router-dom";
|
|
2
|
+
import { useNavigate, useSearchParams } from "react-router-dom";
|
|
3
3
|
import { Plus, Send } from "lucide-react";
|
|
4
4
|
import { Section, StatusDot } from "../components/Section";
|
|
5
5
|
import { Badge, Button, Empty, Loading, Switch } from "../components/ui";
|
|
6
|
+
import { Tip } from "../components/ui/tip";
|
|
6
7
|
import { Admin, Projects, Telegram } from "../lib/api";
|
|
7
8
|
import { useToast } from "../components/Toast";
|
|
8
9
|
import { useDaemonStatus } from "../hooks/useDaemonStatus";
|
|
@@ -17,6 +18,7 @@ import type { TelegramChannel } from "../types/daemon";
|
|
|
17
18
|
|
|
18
19
|
export function ApxAdminScreen() {
|
|
19
20
|
const navigate = useNavigate();
|
|
21
|
+
const [params, setParams] = useSearchParams();
|
|
20
22
|
const toast = useToast();
|
|
21
23
|
const { health, isUp } = useDaemonStatus();
|
|
22
24
|
const { projects, isLoading: projLoading, mutate: mutateProjects } = useProjects();
|
|
@@ -57,8 +59,14 @@ export function ApxAdminScreen() {
|
|
|
57
59
|
<p className="text-sm text-muted-fg">{t("admin.subtitle")}</p>
|
|
58
60
|
</div>
|
|
59
61
|
<div className="flex gap-2">
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
+
<Tip content={t("daemon.reload_hint")}>
|
|
63
|
+
<Button size="sm" onClick={reload}>{t("common.reload")} config</Button>
|
|
64
|
+
</Tip>
|
|
65
|
+
<Button size="sm" variant="primary" onClick={() => {
|
|
66
|
+
const next = new URLSearchParams(params);
|
|
67
|
+
next.set("action", "add-project");
|
|
68
|
+
setParams(next);
|
|
69
|
+
}}>
|
|
62
70
|
<Plus size={14} /> {t("nav.project")}
|
|
63
71
|
</Button>
|
|
64
72
|
</div>
|
|
@@ -3,6 +3,7 @@ import { RefreshCw } from "lucide-react";
|
|
|
3
3
|
import { Deck } from "../../lib/api/deck";
|
|
4
4
|
import { Section } from "../../components/Section";
|
|
5
5
|
import { Button, Empty, Loading } from "../../components/ui";
|
|
6
|
+
import { Tip } from "../../components/ui/tip";
|
|
6
7
|
import { useToast } from "../../components/Toast";
|
|
7
8
|
import { DaemonCard } from "../../components/deck/DaemonCard";
|
|
8
9
|
import { DesktopGroup } from "../../components/deck/DesktopGroup";
|
|
@@ -91,9 +92,11 @@ export function DeckScreen() {
|
|
|
91
92
|
: t("modules_ui.deck_widgets_summary", { count: widgets.length, enabled: enabledCount })
|
|
92
93
|
}
|
|
93
94
|
action={
|
|
94
|
-
<
|
|
95
|
-
<
|
|
96
|
-
|
|
95
|
+
<Tip content={t("deck_screen.reload_manifest")}>
|
|
96
|
+
<Button size="sm" variant="ghost" onClick={() => mutate()} disabled={isLoading} aria-label={t("deck_screen.reload_manifest")}>
|
|
97
|
+
<RefreshCw size={14} className={isLoading ? "animate-spin" : ""} />
|
|
98
|
+
</Button>
|
|
99
|
+
</Tip>
|
|
97
100
|
}
|
|
98
101
|
>
|
|
99
102
|
{isLoading && <Loading label={t("modules_ui.deck_loading_manifest_full")} />}
|
|
@@ -9,6 +9,7 @@ import { Agents, Conversations, Messages, Routines, Tasks, Tools } from "../../l
|
|
|
9
9
|
import type { AgentDetail, AgentEntry, MessageEntry, RoutineEntry } from "../../types/daemon";
|
|
10
10
|
import { Section } from "../../components/Section";
|
|
11
11
|
import { Badge, Button, Field, Input, Loading, Switch, Textarea } from "../../components/ui";
|
|
12
|
+
import { Tip } from "../../components/ui/tip";
|
|
12
13
|
import { UiSelect } from "../../components/UiSelect";
|
|
13
14
|
import { useToast } from "../../components/Toast";
|
|
14
15
|
import { cn } from "../../lib/cn";
|
|
@@ -405,11 +406,13 @@ function ToolsPicker({ value, onChange }: { value: string; onChange: (v: string)
|
|
|
405
406
|
{catalog.map((tool) => {
|
|
406
407
|
const on = selected.includes(tool.name);
|
|
407
408
|
return (
|
|
408
|
-
<
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
409
|
+
<Tip key={tool.name} content={tool.description || tool.name}>
|
|
410
|
+
<button type="button" onClick={() => toggle(tool.name)}
|
|
411
|
+
className={cn("rounded-md border px-2 py-0.5 font-mono text-[11px] transition-colors",
|
|
412
|
+
on ? "border-emerald-500/50 bg-emerald-500/10 text-emerald-400" : "border-border text-muted-fg hover:text-foreground")}>
|
|
413
|
+
{tool.name}
|
|
414
|
+
</button>
|
|
415
|
+
</Tip>
|
|
413
416
|
);
|
|
414
417
|
})}
|
|
415
418
|
{custom.map((s) => (
|
|
@@ -7,6 +7,7 @@ import { Mcps, Vars, type McpAddBody, type McpScope, type McpTestResult, type Mc
|
|
|
7
7
|
import type { McpEntry } from "../../types/daemon";
|
|
8
8
|
import { Section } from "../../components/Section";
|
|
9
9
|
import { Badge, Button, Dialog, Empty, Field, Input, Loading, Switch } from "../../components/ui";
|
|
10
|
+
import { Tip } from "../../components/ui/tip";
|
|
10
11
|
import { UiSelect } from "../../components/UiSelect";
|
|
11
12
|
import { VarTokenInput } from "../../components/inputs/VarTokenInput";
|
|
12
13
|
import { KeyValueList, recordFromRows, rowsFromRecord, type KvRow } from "../../components/inputs/KeyValueList";
|
|
@@ -122,16 +123,22 @@ export function McpsTab({ pid }: { pid: string }) {
|
|
|
122
123
|
label=""
|
|
123
124
|
/>
|
|
124
125
|
</div>
|
|
125
|
-
<
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<Pencil size={13} />
|
|
126
|
+
<Tip content={t("project.mcps.test_btn")}>
|
|
127
|
+
<Button size="sm" variant="ghost" onClick={(e) => { e.stopPropagation(); runTest(m.name); }} aria-label={t("project.mcps.test_btn")}>
|
|
128
|
+
<FlaskConical size={13} />
|
|
129
|
+
</Button>
|
|
130
|
+
</Tip>
|
|
131
|
+
<Tip content={t("project.mcps.logs_btn")}>
|
|
132
|
+
<Button size="sm" variant="ghost" onClick={(e) => { e.stopPropagation(); setActiveMcp(m.name); }} aria-label={t("project.mcps.logs_btn")}>
|
|
133
|
+
<ScrollText size={13} />
|
|
134
134
|
</Button>
|
|
135
|
+
</Tip>
|
|
136
|
+
{writable && (
|
|
137
|
+
<Tip content={t("project.mcps.edit_btn")}>
|
|
138
|
+
<Button size="sm" variant="ghost" onClick={(e) => { e.stopPropagation(); setDialog({ kind: "edit", entry: m }); }} aria-label={t("project.mcps.edit_btn")}>
|
|
139
|
+
<Pencil size={13} />
|
|
140
|
+
</Button>
|
|
141
|
+
</Tip>
|
|
135
142
|
)}
|
|
136
143
|
{writable && (
|
|
137
144
|
<Button size="sm" variant="destructive" onClick={(e) => { e.stopPropagation(); remove(m.name, scopeForRemove); }}>
|