@agentprojectcontext/apx 1.34.0 → 1.35.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/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-C0fm31dY.js +618 -0
- package/src/interfaces/web/dist/assets/index-C0fm31dY.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-UcAqlBO6.css +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +21 -1
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +68 -0
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +222 -0
- package/src/interfaces/web/src/hooks/useChat.ts +19 -0
- package/src/interfaces/web/src/i18n/en.ts +1 -0
- package/src/interfaces/web/src/i18n/es.ts +1 -0
- package/src/interfaces/web/src/lib/api/skills.ts +70 -0
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +6 -2
- 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/package.json
CHANGED
package/skills/apx/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: apx
|
|
|
3
3
|
description: >-
|
|
4
4
|
APX CLI — local daemon that orchestrates agents, sessions, MCPs, and channels across CLIs.
|
|
5
5
|
Use `apx exec "prompt"` for the local super-agent, or `apx run <agent> --runtime <claude-code|codex|opencode|aider|cursor-agent|gemini-cli|qwen-code> "prompt"` to hand the task to another CLI.
|
|
6
|
-
Activate on: 'apx', 'apx exec', 'apx run', 'apx daemon', '
|
|
6
|
+
Activate on: 'apx', 'apx exec', 'apx run', 'apx daemon', 'ask codex/claude/opencode/gemini to …', 'have <runtime> do …', 'delegate to another runtime', 'run this in <runtime>', 'route this task to <runtime>'.
|
|
7
7
|
homepage: https://github.com/agentprojectcontext/apx
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -1,16 +1,26 @@
|
|
|
1
|
+
// System prompt for project agents (Cody, Sofía, etc.). Shares the agent-base
|
|
2
|
+
// + action discipline with the super-agent, layered with a project-agent role
|
|
3
|
+
// delta plus the agent's own profile fields.
|
|
4
|
+
//
|
|
5
|
+
// When a project agent answers through a real user channel (Telegram, web,
|
|
6
|
+
// desktop), pass `channel` / `channelMeta` / `sender` so the channel-context,
|
|
7
|
+
// relationship and voice-mode / segmenting blocks come along — without that
|
|
8
|
+
// the agent has no idea HOW the user is talking to it.
|
|
1
9
|
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
10
|
import { readAgentMemory } from "./memory.js";
|
|
5
11
|
import { apcProjectFile, apcSkillFile } from "../apc/paths.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
PROMPTS,
|
|
14
|
+
buildChannelContextBlock,
|
|
15
|
+
buildVoiceModeBlock,
|
|
16
|
+
buildRelationshipBlock,
|
|
17
|
+
buildUserContextBlock,
|
|
18
|
+
buildSegmentDiscipline,
|
|
19
|
+
} from "./prompt-builder.js";
|
|
20
|
+
|
|
21
|
+
// Cap the injected agent body so an over-long authored file can't blow the
|
|
22
|
+
// token budget. Mirrors PROJECT_AGENTS_MAX_CHARS for AGENTS.md.
|
|
23
|
+
const AGENT_BODY_MAX_CHARS = 6000;
|
|
14
24
|
|
|
15
25
|
function listField(value) {
|
|
16
26
|
if (Array.isArray(value)) return value.map(String).map((s) => s.trim()).filter(Boolean);
|
|
@@ -21,9 +31,9 @@ function projectName(project) {
|
|
|
21
31
|
if (project?.name) return project.name;
|
|
22
32
|
try {
|
|
23
33
|
const meta = JSON.parse(fs.readFileSync(apcProjectFile(project.path), "utf8"));
|
|
24
|
-
return meta.name ||
|
|
34
|
+
return meta.name || project.path?.split("/").pop() || "";
|
|
25
35
|
} catch {
|
|
26
|
-
return path.
|
|
36
|
+
return project?.path?.split("/").pop() || "";
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
|
|
@@ -31,80 +41,146 @@ export function agentSkills(agent) {
|
|
|
31
41
|
return listField(agent?.fields?.Skills);
|
|
32
42
|
}
|
|
33
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Build the system prompt for a project agent.
|
|
46
|
+
*
|
|
47
|
+
* @param project { id, name, path, ... }
|
|
48
|
+
* @param agent { slug, fields: { Description, Role, Language, Skills, Tools, ... }, body }
|
|
49
|
+
* @param opts
|
|
50
|
+
* @param opts.invocation "engine" (direct LLM call), "telegram", "routine", etc.
|
|
51
|
+
* @param opts.runtime external runtime name when relevant ("claude-code", …)
|
|
52
|
+
* @param opts.channel surface the user is on (channels/<name>.md is layered in)
|
|
53
|
+
* @param opts.channelMeta meta for the channel template + `{voice: true}` flag
|
|
54
|
+
* @param opts.sender resolved sender for the relationship block
|
|
55
|
+
* @param opts.caller who invoked us (another agent slug, "user", "routine", …)
|
|
56
|
+
* @param opts.routine routine name when invocation === "routine"
|
|
57
|
+
* @param opts.globalConfig used for user.language / user.locale / user.timezone
|
|
58
|
+
* @param opts.extraParts additional blocks to append before discipline
|
|
59
|
+
*/
|
|
34
60
|
export function buildAgentSystem(project, agent, {
|
|
35
61
|
invocation = "engine",
|
|
36
62
|
runtime = null,
|
|
37
63
|
channel = null,
|
|
64
|
+
channelMeta = {},
|
|
65
|
+
sender = null,
|
|
38
66
|
caller = null,
|
|
39
67
|
routine = null,
|
|
68
|
+
globalConfig = {},
|
|
40
69
|
extraParts = [],
|
|
41
70
|
} = {}) {
|
|
42
71
|
const fields = agent.fields || {};
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
`Project: ${projectName(project)} (${project.path}).`,
|
|
46
|
-
];
|
|
72
|
+
const channelLow = String(channel || "").toLowerCase();
|
|
73
|
+
const voice = !!channelMeta?.voice || channelLow === "voice";
|
|
47
74
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (fields.Language) parts.push(`Default language: ${fields.Language}`);
|
|
75
|
+
// Shared base + project-agent role delta (the "I'm scoped to one project" framing).
|
|
76
|
+
const roleBlock = [PROMPTS.AGENT_BASE, PROMPTS.PROJECT_AGENT_ROLE].join("\n\n");
|
|
51
77
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
// Agent profile (its display name + description + Role + Language + owner from config).
|
|
79
|
+
const profileLines = [
|
|
80
|
+
`# Agent profile`,
|
|
81
|
+
`You are **${agent.slug}**, a project agent dedicated to **${projectName(project)}** (\`${project.path}\`).`,
|
|
82
|
+
];
|
|
83
|
+
if (fields.Description) profileLines.push(fields.Description);
|
|
84
|
+
if (fields.Role) profileLines.push(`Role: ${fields.Role}`);
|
|
85
|
+
if (fields.Language) profileLines.push(`Default language: ${fields.Language}`);
|
|
86
|
+
|
|
87
|
+
// The agent's authored body (everything after the frontmatter in its
|
|
88
|
+
// `.apc/agents/<slug>.md`) is its real instruction set — persona, domain
|
|
89
|
+
// rules, API endpoints, tone, hard limits. Without injecting it the agent
|
|
90
|
+
// runs on its fields alone and loses everything its author actually wrote.
|
|
91
|
+
let customBody = String(agent.body || "").trim();
|
|
92
|
+
if (customBody.length > AGENT_BODY_MAX_CHARS) {
|
|
93
|
+
customBody = customBody.slice(0, AGENT_BODY_MAX_CHARS) + "\n\n…(instructions truncated)";
|
|
61
94
|
}
|
|
95
|
+
const customInstructions = customBody ? `# Custom instructions\n${customBody}` : "";
|
|
62
96
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
if (memory) parts.push("## Memory\n" + memory);
|
|
97
|
+
// User context (owner name, language, timezone) — same block the super-agent
|
|
98
|
+
// gets, so project agents know how to address the user.
|
|
99
|
+
const userContext = buildUserContextBlock(null, globalConfig, { agentName: agent.slug });
|
|
67
100
|
|
|
68
|
-
|
|
69
|
-
|
|
101
|
+
// Channel context — the same channels/*.md the super-agent uses. Project
|
|
102
|
+
// agents talk through the same surfaces; they need the same formatting rules.
|
|
103
|
+
const channelBlock = buildChannelContextBlock(channel, channelMeta);
|
|
104
|
+
const voiceBlock = buildVoiceModeBlock(voice);
|
|
105
|
+
const segmentDiscipline = buildSegmentDiscipline({ channel: channelLow, voice });
|
|
70
106
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (fs.existsSync(skillPath)) parts.push(`## Skill: ${skill}\n` + fs.readFileSync(skillPath, "utf8"));
|
|
74
|
-
}
|
|
107
|
+
// Relationship block — "you're talking to <owner>" / "<contact>" / "<guest>".
|
|
108
|
+
const relationship = buildRelationshipBlock(sender);
|
|
75
109
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
110
|
+
// Declared tool hints (informational — actual callables come from runtime).
|
|
111
|
+
const declaredTools = listField(fields.Tools);
|
|
112
|
+
const toolHints = declaredTools.length
|
|
113
|
+
? [
|
|
114
|
+
"## Declared tool hints (agent-level expectations)",
|
|
115
|
+
declaredTools.join(", "),
|
|
116
|
+
"Actual callable tools depend on the invocation surface — use whatever the runtime sends this turn.",
|
|
117
|
+
].join("\n")
|
|
118
|
+
: "";
|
|
79
119
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
parts.push(ACTION_DISCIPLINE_RULES);
|
|
120
|
+
// Invocation context (who called me, through what, for what).
|
|
121
|
+
const invocationCtx = buildInvocationContext({ invocation, runtime, caller, routine });
|
|
83
122
|
|
|
84
|
-
|
|
123
|
+
// Per-agent memory (lives under <project>/.apc/agents/<slug>/memory.md).
|
|
124
|
+
const memory = readAgentMemory(project, agent.slug);
|
|
125
|
+
const memoryBlock = memory ? "# Memory\n" + memory : "";
|
|
126
|
+
|
|
127
|
+
// Project's APX skill + agent's declared skills (loaded as full bodies — they're
|
|
128
|
+
// small and specific to this agent).
|
|
129
|
+
const projectSkills = buildProjectSkills(project, agent);
|
|
130
|
+
|
|
131
|
+
return [
|
|
132
|
+
roleBlock,
|
|
133
|
+
profileLines.join("\n"),
|
|
134
|
+
customInstructions,
|
|
135
|
+
userContext,
|
|
136
|
+
memoryBlock,
|
|
137
|
+
relationship,
|
|
138
|
+
channelBlock,
|
|
139
|
+
toolHints,
|
|
140
|
+
invocationCtx,
|
|
141
|
+
projectSkills,
|
|
142
|
+
...extraParts.filter(Boolean),
|
|
143
|
+
voiceBlock,
|
|
144
|
+
PROMPTS.ACTION_DISCIPLINE,
|
|
145
|
+
segmentDiscipline,
|
|
146
|
+
]
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
.join("\n\n");
|
|
85
149
|
}
|
|
86
150
|
|
|
87
|
-
function buildInvocationContext({ invocation, runtime,
|
|
88
|
-
const lines = [
|
|
89
|
-
"## Invocation Context",
|
|
90
|
-
`invocation: ${invocation}`,
|
|
91
|
-
];
|
|
151
|
+
function buildInvocationContext({ invocation, runtime, caller, routine }) {
|
|
152
|
+
const lines = [`## Invocation`, `invocation: ${invocation}`];
|
|
92
153
|
if (runtime) lines.push(`runtime: ${runtime}`);
|
|
93
|
-
if (channel) lines.push(`channel: ${channel}`);
|
|
94
154
|
if (caller) lines.push(`caller: ${caller}`);
|
|
95
155
|
if (routine) lines.push(`routine: ${routine}`);
|
|
96
156
|
|
|
97
157
|
if (runtime) {
|
|
98
158
|
lines.push(
|
|
99
|
-
"You
|
|
159
|
+
"You're running inside the named external runtime. Use only tools and permissions that runtime exposes."
|
|
100
160
|
);
|
|
101
|
-
} else if (invocation === "engine") {
|
|
102
|
-
lines.push("You are a direct LLM call through APX. Do not claim shell, file, MCP, or Telegram tools unless APX explicitly provided them.");
|
|
103
|
-
} else if (invocation === "telegram") {
|
|
104
|
-
lines.push("You are replying through Telegram. Keep responses brief, plain text, and matched to the user's language.");
|
|
105
161
|
} else if (invocation === "routine") {
|
|
106
|
-
lines.push(
|
|
162
|
+
lines.push(
|
|
163
|
+
"You were invoked by an APX routine. Complete the requested work now; don't say you will do it later."
|
|
164
|
+
);
|
|
165
|
+
} else if (invocation === "engine") {
|
|
166
|
+
lines.push(
|
|
167
|
+
"You're a direct LLM call through APX. Don't claim shell, file, MCP, or Telegram tools unless the runtime explicitly sent them this turn."
|
|
168
|
+
);
|
|
107
169
|
}
|
|
108
|
-
|
|
109
170
|
return lines.join("\n");
|
|
110
171
|
}
|
|
172
|
+
|
|
173
|
+
function buildProjectSkills(project, agent) {
|
|
174
|
+
const parts = [];
|
|
175
|
+
const apxSkill = apcSkillFile(project.path, "apx");
|
|
176
|
+
if (fs.existsSync(apxSkill)) {
|
|
177
|
+
parts.push("## APX\n" + fs.readFileSync(apxSkill, "utf8").trim());
|
|
178
|
+
}
|
|
179
|
+
for (const skill of agentSkills(agent)) {
|
|
180
|
+
const skillPath = apcSkillFile(project.path, skill);
|
|
181
|
+
if (fs.existsSync(skillPath)) {
|
|
182
|
+
parts.push(`## Skill: ${skill}\n` + fs.readFileSync(skillPath, "utf8").trim());
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return parts.join("\n\n");
|
|
186
|
+
}
|
|
@@ -86,13 +86,13 @@ export function buildVoiceChannelContext(channel, { projectId, language = "es" }
|
|
|
86
86
|
switch (channel) {
|
|
87
87
|
case "voice":
|
|
88
88
|
return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: CHANNELS.DECK, channelMeta: { voice: true } };
|
|
89
|
-
case
|
|
89
|
+
case CHANNELS.DECK:
|
|
90
90
|
return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: CHANNELS.DECK, channelMeta: {} };
|
|
91
|
-
case
|
|
91
|
+
case CHANNELS.DESKTOP:
|
|
92
92
|
return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: CHANNELS.DESKTOP, channelMeta: { voice: true } };
|
|
93
|
-
case
|
|
93
|
+
case CHANNELS.TELEGRAM:
|
|
94
94
|
return { ...base, contextNote: dynamicNote, channel: CHANNELS.TELEGRAM, channelMeta: {} };
|
|
95
95
|
default:
|
|
96
|
-
return { ...base, contextNote: dynamicNote, channel: channel ||
|
|
96
|
+
return { ...base, contextNote: dynamicNote, channel: channel || CHANNELS.API, channelMeta: {} };
|
|
97
97
|
}
|
|
98
98
|
}
|