@agentprojectcontext/apx 1.34.0 → 1.36.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/skills/apx/SKILL.md +1 -1
- package/src/core/agent/build-agent-system.js +134 -58
- package/src/core/agent/channels/voice-context.js +4 -4
- package/src/core/agent/prompt-builder.js +176 -123
- package/src/core/agent/prompts/channels/code.md +12 -10
- package/src/core/agent/prompts/channels/desktop.md +5 -32
- package/src/core/agent/prompts/channels/telegram.md +4 -15
- package/src/core/agent/prompts/channels/web_code.md +11 -11
- package/src/core/agent/prompts/core/agent-base.md +24 -0
- package/src/core/agent/prompts/core/project-agent.md +11 -0
- package/src/core/agent/prompts/core/super-agent.md +21 -0
- package/src/core/agent/prompts/discipline/action.md +10 -0
- package/src/core/agent/prompts/discipline/single-segment.md +6 -0
- package/src/core/agent/prompts/discipline/two-segment.md +11 -0
- package/src/core/agent/self-memory.js +43 -1
- package/src/core/agent/skills/index-store.js +307 -0
- package/src/core/agent/skills/index.js +15 -1
- package/src/core/agent/skills/inspector.js +317 -0
- package/src/core/agent/super-agent.js +7 -1
- package/src/core/agent/tools/handlers/_git.js +50 -0
- package/src/core/agent/tools/handlers/git-diff.js +44 -0
- package/src/core/agent/tools/handlers/git-log.js +38 -0
- package/src/core/agent/tools/handlers/git-show.js +34 -0
- package/src/core/agent/tools/handlers/git-status.js +61 -0
- package/src/core/agent/tools/names.js +31 -0
- package/src/core/agent/tools/registry.js +36 -5
- package/src/core/config/index.js +21 -0
- package/src/core/runtime-skills/apx/SKILL.md +27 -39
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +40 -56
- package/src/core/runtime-skills/apx-agent/SKILL.md +27 -30
- package/src/core/runtime-skills/apx-mcp/SKILL.md +31 -36
- package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +37 -51
- package/src/core/runtime-skills/apx-project/SKILL.md +20 -29
- package/src/core/runtime-skills/apx-routine/SKILL.md +34 -47
- package/src/core/runtime-skills/apx-runtime/SKILL.md +32 -50
- package/src/core/runtime-skills/apx-sessions/SKILL.md +96 -145
- package/src/core/runtime-skills/apx-skill-builder/SKILL.md +53 -77
- package/src/core/runtime-skills/apx-task/SKILL.md +18 -21
- package/src/core/runtime-skills/apx-telegram/SKILL.md +43 -54
- package/src/core/runtime-skills/apx-voice/SKILL.md +36 -56
- package/src/core/stores/conversations.js +27 -2
- package/src/host/daemon/api/exec.js +2 -0
- package/src/host/daemon/api/skills.js +140 -6
- package/src/host/daemon/api/super-agent.js +56 -1
- package/src/host/daemon/index.js +17 -0
- package/src/interfaces/cli/branding.js +53 -0
- package/src/interfaces/cli/commands/skills.js +254 -0
- package/src/interfaces/cli/index.js +84 -2
- package/src/interfaces/web/dist/assets/index-Cm0KyPoZ.css +1 -0
- package/src/interfaces/web/dist/assets/index-DJKA763h.js +628 -0
- package/src/interfaces/web/dist/assets/index-DJKA763h.js.map +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/src/App.tsx +0 -1
- package/src/interfaces/web/src/components/chat/ChatList.tsx +412 -0
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +21 -1
- package/src/interfaces/web/src/components/settings/AppearancePanel.tsx +1 -1
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +69 -1
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +222 -0
- package/src/interfaces/web/src/hooks/useChat.ts +54 -2
- package/src/interfaces/web/src/i18n/en.ts +12 -1
- package/src/interfaces/web/src/i18n/es.ts +12 -1
- package/src/interfaces/web/src/lib/api/agents.ts +1 -1
- package/src/interfaces/web/src/lib/api/skills.ts +70 -0
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +3 -5
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +12 -6
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +120 -87
- package/src/interfaces/web/src/types/daemon.ts +10 -0
- package/src/core/agent/prompts/action-discipline.md +0 -24
- package/src/core/agent/prompts/super-agent-base.md +0 -42
- package/src/interfaces/web/dist/assets/index-DdmSRtsz.css +0 -1
- package/src/interfaces/web/dist/assets/index-M4FspaCH.js +0 -613
- package/src/interfaces/web/dist/assets/index-M4FspaCH.js.map +0 -1
- package/src/interfaces/web/src/screens/project/ThreadsTab.tsx +0 -100
|
@@ -4,11 +4,11 @@ import useSWR from "swr";
|
|
|
4
4
|
import { Plus, Trash2 } from "lucide-react";
|
|
5
5
|
import { Agents } from "../../lib/api";
|
|
6
6
|
import { Badge, Button, Dialog, Empty, Field, Input, Loading, Switch } from "../../components/ui";
|
|
7
|
-
import { UiSelect } from "../../components/UiSelect";
|
|
8
7
|
import { Composer } from "../../components/chat/Composer";
|
|
9
8
|
import { MessageList } from "../../components/chat/MessageList";
|
|
10
9
|
import { ContextBar } from "../../components/chat/ContextBar";
|
|
11
10
|
import { InlineAskPanel, pendingAskQuestions } from "../../components/chat/InlineAskPanel";
|
|
11
|
+
import { ChatList, type ChatKey } from "../../components/chat/ChatList";
|
|
12
12
|
import { useChat } from "../../hooks/useChat";
|
|
13
13
|
import { useToast } from "../../components/Toast";
|
|
14
14
|
import { t } from "../../i18n";
|
|
@@ -24,48 +24,56 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
24
24
|
const toast = useToast();
|
|
25
25
|
const [params] = useSearchParams();
|
|
26
26
|
const agents = useSWR(`/projects/${pid}/agents`, () => Agents.list(pid));
|
|
27
|
-
const [activeSlug, setActiveSlug] = useState(params.get("agent") || "");
|
|
28
27
|
const [creating, setCreating] = useState(false);
|
|
29
28
|
const [model, setModel] = useState("");
|
|
30
29
|
const [dismissedAskKey, setDismissedAskKey] = useState<string | null>(null);
|
|
31
|
-
const { msgs, send: sendChat, stop, clear, streaming } =
|
|
30
|
+
const { msgs, send: sendChat, stop, clear, load, streaming, conversationId } =
|
|
31
|
+
useChat(pid, (m) => toast.error(m));
|
|
32
32
|
const persona = usePersonaName();
|
|
33
33
|
|
|
34
|
+
// Selection state — drives both the sidebar highlight and the right-pane
|
|
35
|
+
// header. Defaults to a live session with the super-agent so the chat works
|
|
36
|
+
// even on a brand-new project with zero agents and zero conversations.
|
|
37
|
+
const initialFromUrl = params.get("agent");
|
|
38
|
+
const [selected, setSelected] = useState<ChatKey>(
|
|
39
|
+
initialFromUrl
|
|
40
|
+
? { kind: "live", agentSlug: initialFromUrl }
|
|
41
|
+
: { kind: "live", agentSlug: ROBY_SLUG },
|
|
42
|
+
);
|
|
43
|
+
|
|
34
44
|
const agentList = agents.data || [];
|
|
35
|
-
// Virtual options shown in the dropdown — the super-agent is always first,
|
|
36
|
-
// then the real project agents. It works on every project (calls
|
|
37
|
-
// /projects/:pid/super-agent/chat) so we expose it everywhere, not just /base.
|
|
38
45
|
const isRoby = (slug: string | null | undefined) => slug === ROBY_SLUG;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{ value: ROBY_SLUG, label: `${persona} (super-agent)` },
|
|
42
|
-
...agentList.map((a) => ({ value: a.slug, label: a.slug })),
|
|
43
|
-
],
|
|
44
|
-
[agentList, persona],
|
|
45
|
-
);
|
|
46
|
+
|
|
47
|
+
// The agent whose dropdown badge / model we show on the right header.
|
|
46
48
|
const activeAgent = useMemo(
|
|
47
|
-
() =>
|
|
48
|
-
|
|
49
|
+
() =>
|
|
50
|
+
selected.kind === "live"
|
|
51
|
+
? agentList.find((a) => a.slug === selected.agentSlug)
|
|
52
|
+
: agentList.find((a) => a.slug === selected.agentSlug),
|
|
53
|
+
[agentList, selected],
|
|
49
54
|
);
|
|
50
|
-
|
|
51
|
-
// real agent, or Roby when the project has no agents at all.
|
|
52
|
-
const effectiveSlug = isRoby(activeSlug)
|
|
53
|
-
? ROBY_SLUG
|
|
54
|
-
: (activeAgent?.slug || ROBY_SLUG);
|
|
55
|
-
const activeIsRoby = effectiveSlug === ROBY_SLUG;
|
|
55
|
+
const activeIsRoby = isRoby(selected.agentSlug);
|
|
56
56
|
|
|
57
|
+
// Whenever the user picks a stored conversation, reload the in-memory chat
|
|
58
|
+
// with its persisted history. The hook itself binds the conversation_id so
|
|
59
|
+
// subsequent sends append to the same file.
|
|
57
60
|
useEffect(() => {
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
if (selected.kind === "conv") {
|
|
62
|
+
void load(selected.agentSlug, selected.convId);
|
|
63
|
+
} else {
|
|
64
|
+
// Switching to a live session = drop any previously bound conversation.
|
|
65
|
+
if (conversationId) clear();
|
|
66
|
+
}
|
|
67
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
+
}, [selected.kind, selected.kind === "conv" ? selected.convId : selected.agentSlug]);
|
|
62
69
|
|
|
63
70
|
const send = async (text: string) => {
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
if (activeIsRoby) {
|
|
72
|
+
await sendChat(text, { model: model || undefined });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!activeAgent) return;
|
|
76
|
+
await sendChat(text, { model: model || undefined, agentSlug: activeAgent.slug });
|
|
69
77
|
};
|
|
70
78
|
|
|
71
79
|
const copyToClipboard = async (text: string) => {
|
|
@@ -73,72 +81,97 @@ export function ChatTab({ pid }: { pid: string }) {
|
|
|
73
81
|
catch { /* ignore */ }
|
|
74
82
|
};
|
|
75
83
|
|
|
76
|
-
|
|
84
|
+
const onNewChat = () => {
|
|
85
|
+
setSelected({ kind: "live", agentSlug: ROBY_SLUG });
|
|
86
|
+
clear();
|
|
87
|
+
};
|
|
77
88
|
|
|
89
|
+
const headerTitle = activeIsRoby
|
|
90
|
+
? t("project.chat.superagent_title", { persona })
|
|
91
|
+
: selected.kind === "conv"
|
|
92
|
+
? selected.convId
|
|
93
|
+
: t("project.chat.title");
|
|
78
94
|
const headerSubtitle = activeIsRoby
|
|
79
95
|
? t("project.chat.superagent_subtitle", { persona })
|
|
80
|
-
:
|
|
96
|
+
: selected.kind === "conv"
|
|
97
|
+
? t("project.chat.loaded_subtitle", { slug: selected.agentSlug })
|
|
98
|
+
: t("project.chat.subtitle");
|
|
99
|
+
|
|
100
|
+
if (agents.isLoading) return <Loading />;
|
|
81
101
|
|
|
82
102
|
return (
|
|
83
|
-
<div className="flex h-full
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
<div className="flex h-full overflow-hidden rounded-xl border border-border bg-card/40">
|
|
104
|
+
<ChatList
|
|
105
|
+
pid={pid}
|
|
106
|
+
agents={agentList}
|
|
107
|
+
superAgentSlug={ROBY_SLUG}
|
|
108
|
+
superAgentLabel={`${persona} (super-agent)`}
|
|
109
|
+
selected={selected}
|
|
110
|
+
onSelect={setSelected}
|
|
111
|
+
onNewChat={onNewChat}
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
<section className="flex min-w-0 flex-1 flex-col">
|
|
115
|
+
<header className="flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3">
|
|
116
|
+
<div className="min-w-0">
|
|
117
|
+
<h2 className="truncate text-sm font-semibold">{headerTitle}</h2>
|
|
118
|
+
<p className="truncate text-[11px] text-muted-fg">{headerSubtitle}</p>
|
|
98
119
|
</div>
|
|
99
|
-
|
|
100
|
-
?
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
120
|
+
<div className="flex items-center gap-2">
|
|
121
|
+
{activeIsRoby ? (
|
|
122
|
+
<Badge tone="success">super-agent</Badge>
|
|
123
|
+
) : (
|
|
124
|
+
activeAgent?.model && <Badge tone="info">{activeAgent.model}</Badge>
|
|
125
|
+
)}
|
|
126
|
+
{selected.kind === "conv" && <Badge tone="info">{conversationId || "…"}</Badge>}
|
|
127
|
+
{!agentList.length && !activeIsRoby && (
|
|
128
|
+
<Button variant="primary" size="sm" onClick={() => setCreating(true)}>
|
|
129
|
+
<Plus size={14} /> {t("project.chat.create_agent")}
|
|
130
|
+
</Button>
|
|
131
|
+
)}
|
|
132
|
+
<Button
|
|
133
|
+
variant="ghost"
|
|
134
|
+
size="sm"
|
|
135
|
+
disabled={streaming || msgs.length === 0}
|
|
136
|
+
onClick={onNewChat}
|
|
137
|
+
>
|
|
138
|
+
<Trash2 size={13} /> {t("project.chat.clear")}
|
|
105
139
|
</Button>
|
|
140
|
+
</div>
|
|
141
|
+
</header>
|
|
142
|
+
|
|
143
|
+
<div className="flex-1 overflow-y-auto">
|
|
144
|
+
{msgs.length ? (
|
|
145
|
+
<MessageList msgs={msgs} onCopy={copyToClipboard} />
|
|
146
|
+
) : (
|
|
147
|
+
<div className="flex h-full items-center justify-center p-8">
|
|
148
|
+
<p className="text-sm text-muted-fg">{t("project.chat.empty")}</p>
|
|
149
|
+
</div>
|
|
106
150
|
)}
|
|
107
|
-
<Button variant="ghost" size="sm" disabled={streaming || msgs.length === 0} onClick={resetConversation}>
|
|
108
|
-
<Trash2 size={13} /> {t("project.chat.clear")}
|
|
109
|
-
</Button>
|
|
110
151
|
</div>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
})()}
|
|
135
|
-
<Composer
|
|
136
|
-
onSend={send}
|
|
137
|
-
onStop={stop}
|
|
138
|
-
streaming={streaming}
|
|
139
|
-
model={model}
|
|
140
|
-
onModelChange={setModel}
|
|
141
|
-
/>
|
|
152
|
+
<ContextBar msgs={msgs} />
|
|
153
|
+
{(() => {
|
|
154
|
+
const pending = !streaming ? pendingAskQuestions(msgs) : null;
|
|
155
|
+
if (!pending || pending.turnKey === dismissedAskKey) return null;
|
|
156
|
+
return (
|
|
157
|
+
<InlineAskPanel
|
|
158
|
+
turnKey={pending.turnKey}
|
|
159
|
+
questions={pending.questions}
|
|
160
|
+
onSubmit={(compiled) => void send(compiled)}
|
|
161
|
+
onDismiss={() => setDismissedAskKey(pending.turnKey)}
|
|
162
|
+
disabled={streaming}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
})()}
|
|
166
|
+
<Composer
|
|
167
|
+
onSend={send}
|
|
168
|
+
onStop={stop}
|
|
169
|
+
streaming={streaming}
|
|
170
|
+
model={model}
|
|
171
|
+
onModelChange={setModel}
|
|
172
|
+
/>
|
|
173
|
+
</section>
|
|
174
|
+
|
|
142
175
|
<CreateAgentDialog
|
|
143
176
|
open={creating}
|
|
144
177
|
pid={pid}
|
|
@@ -284,6 +284,16 @@ export interface ChatStreamEvent {
|
|
|
284
284
|
streak?: number;
|
|
285
285
|
// tool_start / tool_result / tool_deduped
|
|
286
286
|
trace?: ToolTrace;
|
|
287
|
+
// skill_inspector: which skills the per-turn RAG loaded/hinted this turn
|
|
288
|
+
inspector?: {
|
|
289
|
+
enabled?: boolean;
|
|
290
|
+
reason?: string;
|
|
291
|
+
embedder?: string;
|
|
292
|
+
scored?: { slug: string; sim: number }[];
|
|
293
|
+
loaded?: string[];
|
|
294
|
+
hinted?: string[];
|
|
295
|
+
jit?: boolean;
|
|
296
|
+
};
|
|
287
297
|
// final
|
|
288
298
|
result?: {
|
|
289
299
|
text?: string;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
## Action Discipline (mandatory)
|
|
2
|
-
- NEVER acknowledge an action without executing it in the same turn. If you are going to do something, call the tool FIRST, then report the result.
|
|
3
|
-
- NEVER use empty acknowledgments like "Ok", "Got it", "Sure", "Understood", "On it", "Give me a moment", "I'll do that now" as standalone responses when a tool call is expected. These are invalid responses.
|
|
4
|
-
- Action first, report after. Produce the tool call in the same response as your acknowledgment.
|
|
5
|
-
- If you cannot execute the action (missing permission, unclear params, tool not available), explain WHY — do not promise and disappear.
|
|
6
|
-
- If the user asks you to do multiple things, do them all in the same turn using sequential tool calls if needed.
|
|
7
|
-
|
|
8
|
-
## Two-segment turns with tools — intro short, answer substantive (mandatory)
|
|
9
|
-
A turn that calls one or more tools produces TWO text segments shown to the user:
|
|
10
|
-
|
|
11
|
-
1. **Pre-tool intro** — a SHORT, NATURAL filler in the user's language BEFORE the tool runs. 2 to 8 words. NEVER contains the answer / data / acknowledgment. Examples: "Dale, voy a anotar eso", "Reviso eso", "Un momento, busco", "Going to remember that".
|
|
12
|
-
2. **Post-tool answer** — the SUBSTANTIVE result AFTER the tool returns. Carries the data, the confirmation, or the next question. Examples: "Listo, anoté que sos Tech Lead en Bytetravel.", "Encontré 3 routines activas: …".
|
|
13
|
-
|
|
14
|
-
Hard rules:
|
|
15
|
-
- The pre-tool intro NEVER includes the substantive content. Do NOT say "Anoté que sos Tech Lead" BEFORE the remember tool runs — at that point the tool hasn't executed yet.
|
|
16
|
-
- The post-tool answer NEVER restates what the intro already said. They serve different purposes: the intro is filler, the answer is the result.
|
|
17
|
-
- Greet AT MOST ONCE per turn. If you already opened with "hola" in the intro, the answer starts with the actual result, no greeting.
|
|
18
|
-
- A turn with NO tool calls produces a single segment — go straight to the answer, no filler intro needed.
|
|
19
|
-
- A simple chit-chat reply (no tool) is one segment: the reply itself.
|
|
20
|
-
|
|
21
|
-
## Chit-chat & greetings (only path out of a forced tool turn)
|
|
22
|
-
- If the user is just greeting, chatting, or thanking you with NO actionable request ("hola", "hi", "buenas", "gracias", "👍", "ok"), you must STILL satisfy the tool-choice contract: call `finish` with a brief friendly reply in the user's language. Do NOT call any other tool just because tools are available — `finish` is the correct tool for chit-chat.
|
|
23
|
-
- A greeting that piggybacks a real request ("hola, listame las rutinas") is NOT chit-chat — handle the request normally with the right tool.
|
|
24
|
-
- When in doubt between chit-chat and a vague request, ask ONE short clarifying question via `finish` — never invent a topic or run an unrelated tool to "be useful".
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Role
|
|
2
|
-
You are **APX itself**, the default daemon-level action agent for Agent Project Context (APC). In code/CLI this role is the *super-agent* — that's the **mode** ("the APX agent talking when no project agent was named"), not your name. Your real name, owner, language, timezone and locale come from the **User & identity** section below; never call yourself "super-agent" to the user.
|
|
3
|
-
|
|
4
|
-
You are an **action agent**, not a chatbot or code explainer: you USE TOOLS to do real things on the user's system. APX (the daemon, config, projects, agents, sessions, message logs) is your own body and toolbox — speak in the first person ("my sessions", "let me check", "I ran…"), never as a third party ("APX can…"). Assume you can do what's asked and reach for the right tool; don't hedge about limits until a tool actually fails.
|
|
5
|
-
|
|
6
|
-
If a message starts with "[audio]", the rest is a speech transcription — treat it as the user's normal message.
|
|
7
|
-
|
|
8
|
-
# Tools
|
|
9
|
-
The runtime sends your exact callable tool schemas on every turn — that is your real capability list. Use them; never recite a tool catalog at the user. On lightweight channels only a core subset is sent; the rest still exist — pull them in by acting, or via load_skill. For factual/inventory questions, CALL a tool first; don't ask the user to specify a project unless the tool fails.
|
|
10
|
-
|
|
11
|
-
You also ship **apx-\* skills** with the exact syntax for multi-step APX operations (routines, projects, MCPs, agents, telegram, runtimes, tasks, voice). When the user needs precise syntax/behavior for one of these, `load_skill` the matching one BEFORE running commands — don't guess flags or invent cron grammar, ports, or paths.
|
|
12
|
-
|
|
13
|
-
# What you must NOT do
|
|
14
|
-
- Don't explain code or describe what a tool *would* do — call it and report the result.
|
|
15
|
-
- Don't give AI disclaimers. You DO have history and memory (see Memory below) — never say "I have no memory of past conversations".
|
|
16
|
-
- Don't tell the user to run an `apx …` command to get info you can fetch with a tool. You operate APX; run the tool yourself. (Only mention CLI when they explicitly ask "how do I do this from the terminal?")
|
|
17
|
-
- Don't end with "give me a second" / "I'll try later", and don't reply with a bare "ok"/"checking"/"one moment". Every message carries a result, finding, or one concrete question.
|
|
18
|
-
- If a message is short or ambiguous, ask ONE short clarifying question in the user's language — don't invent a topic.
|
|
19
|
-
|
|
20
|
-
# Memory & history
|
|
21
|
-
You have durable memory across all channels — never deny it. Two sources:
|
|
22
|
-
- **Sessions & chat logs**: when asked what you worked on, about a "previous/last session", or "what we talked about", call `search_sessions` (defaults to your own apx sessions — pass `engine` only when the user names claude/codex, `all:true` only when they want every engine; pass `id` to open a transcript) and/or `search_messages`. Answer didactically in prose (in the user's language — e.g. "last time we worked on X and Y"), not as a raw list of titles. If your sessions are thin, say so and offer to look across engines — never conclude you "have no history".
|
|
23
|
-
- **Your notebook (self-memory)**: `~/.apx/memory.md`, a bounded slice injected above (as "# Your notebook" or folded into "# Relevant memory"). At the end of any turn where something durable happened (a decision, a completed task, an agreed fact), save the gist with `remember` so your other channels know it too. Keep notes to one self-contained sentence. Use `create_task` for one-off TODOs and project-agent memory for project-scoped facts. When a "# Relevant memory" block is present, treat its bullets as known facts; if a fresh chat opens and something there is still open, bring it up naturally in the user's language (e.g. "yesterday we were on X — shall we continue?") — weave in only what's relevant, don't dump the block.
|
|
24
|
-
|
|
25
|
-
# How you operate
|
|
26
|
-
- APC projects live anywhere on disk; the default workspace is APX home, not a user repo. Registered projects appear below as a tiny index — call tools for details.
|
|
27
|
-
- Permission mode is injected in its own section. total = execute freely. automatico = read/list/safe read-only shell (apx --help, ls, find, rg, grep, docker ps) run directly; destructive/external/runtime/MCP/outbound/config/filesystem-mutating actions need explicit confirmation. permiso = only allowed_tools run directly; the rest need confirmation. When a tool schema has `confirmed`, set confirmed=true only after explicit user confirmation for that exact action.
|
|
28
|
-
- Filesystem search: use targeted tools (find, fd, rg, grep -rn, concrete globs) — never `ls -R` on large trees.
|
|
29
|
-
- Register projects with add_project only — never hand-write AGENTS.md or .apc/project.json via shell.
|
|
30
|
-
- Never paste base64/data-URIs in message text — send images/audio/files via send_telegram media params or paths.
|
|
31
|
-
|
|
32
|
-
# Hard rules
|
|
33
|
-
1. NEVER invent project names, agent slugs, model ids, MCP names, or paths. Look them up via list_* first.
|
|
34
|
-
2. Inventory requests with no project mean **all projects** — call the tool with no project argument; never answer "specify a project" when a global list tool exists.
|
|
35
|
-
3. If a tool errors, retry with different arguments before asking the user.
|
|
36
|
-
4. Write in the user's configured language (see User & identity). Follow the Channel context formatting rules when present. Stay concise unless asked for detail.
|
|
37
|
-
5. Prior turns disambiguate references only ("the first one" → earlier mention); re-call tools for any factual data — past turns are not a cache. /reset or /new means answer fresh.
|
|
38
|
-
6. **SELF-RUN**: "yourself"/"same"/"default"/no agent named → act as APX; don't call list_agents, don't pass an agent argument. **DELEGATE**: a named APC agent → call_agent. **DISPATCH**: an external runtime (claude-code, codex…) → call_runtime, passing the named agent or omitting it to run as yourself. **VAULT**: new agent from a template → list_vault_agents, then import_agent if there's a match.
|
|
39
|
-
7. **Projects**: no project named → use the default workspace. EXCEPTION — routines and project-scoped work need a REAL project: if asked to create a routine (or agent/memory) without a named project, ask which one. Never create routines in the default/id=0 workspace.
|
|
40
|
-
8. **Identity**: user changes their name/your name/personality → set_identity, then confirm.
|
|
41
|
-
9. **Skills on demand**: load_skill only when the user needs exact syntax/behavior matching a skill description (pass project_path from CWD when present) — not for unrelated questions.
|
|
42
|
-
10. **CWD**: when Channel context includes `CWD: <path>`, "this directory/project/here" means that path — use it directly, don't ask.
|