@agentprojectcontext/apx 1.30.2 → 1.31.1
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-agency-agents/SKILL.md +1 -1
- package/skills/apx-agent/SKILL.md +6 -6
- package/skills/apx-project/SKILL.md +1 -2
- package/src/core/agent/prompt-builder.js +6 -0
- package/src/core/agent/run-agent.js +21 -0
- package/src/core/agent/self-memory.js +1 -1
- package/src/core/agent-memory.js +64 -0
- package/src/core/agent-system.js +3 -2
- package/src/core/scaffold.js +43 -18
- package/src/core/tools/browser.js +169 -75
- package/src/core/tools/registry.js +13 -8
- package/src/core/tools/search.js +35 -7
- package/src/host/daemon/api/agents.js +19 -21
- package/src/host/daemon/api/sessions-search.js +1 -1
- package/src/host/daemon/api/shared.js +5 -8
- package/src/host/daemon/super-agent-tools/index.js +232 -43
- package/src/host/daemon/super-agent-tools/registry-bridge.js +30 -1
- package/src/host/daemon/super-agent-tools/tools/discover-tools.js +67 -0
- package/src/host/daemon/super-agent-tools/tools/import-agent.js +2 -0
- package/src/host/daemon/super-agent-tools/tools/read-agent-memory.js +5 -4
- package/src/host/daemon/super-agent.js +15 -17
- package/src/interfaces/cli/commands/agent.js +4 -1
- package/src/interfaces/cli/commands/memory.js +9 -10
- package/src/interfaces/web/dist/assets/{index-CfWyjPBa.js → index-BV615I9p.js} +5 -5
- package/src/interfaces/web/dist/assets/{index-CfWyjPBa.js.map → index-BV615I9p.js.map} +1 -1
- package/src/interfaces/web/dist/index.html +1 -1
- package/src/interfaces/web/package-lock.json +100 -211
- package/src/interfaces/web/src/i18n/en.ts +6 -6
- package/src/interfaces/web/src/i18n/es.ts +6 -6
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// discover_tools — lazy tool discovery + activation.
|
|
2
|
+
//
|
|
3
|
+
// Roby (and any super-agent surface) only carries a small "base" set of tool
|
|
4
|
+
// schemas on lightweight channels (Telegram/desktop/deck) to stay under
|
|
5
|
+
// cheap-tier TPM caps. The rest (browser/Puppeteer, fetch, web_search, runtime,
|
|
6
|
+
// voice, …) exist but are NOT sent to the model by default. This tool is how
|
|
7
|
+
// the model reveals and activates them on demand:
|
|
8
|
+
//
|
|
9
|
+
// discover_tools() → catalog of NOT-loaded tools
|
|
10
|
+
// discover_tools({ category: "browser" }) → activate a whole category
|
|
11
|
+
// discover_tools({ names: ["browser_navigate"] })→ activate specific tools
|
|
12
|
+
//
|
|
13
|
+
// Activation pushes the requested schemas into the per-turn tool session; the
|
|
14
|
+
// agent loop (run-agent.js) merges them into the live schema set so the NEXT
|
|
15
|
+
// model call can actually invoke them. Handlers for every tool already exist —
|
|
16
|
+
// gating is purely about which schemas the model sees.
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: "discover_tools",
|
|
20
|
+
schema: {
|
|
21
|
+
type: "function",
|
|
22
|
+
function: {
|
|
23
|
+
name: "discover_tools",
|
|
24
|
+
description:
|
|
25
|
+
"Discover and activate additional tools that are not loaded by default. " +
|
|
26
|
+
"Call with NO arguments to get the catalog of available-but-not-loaded tools " +
|
|
27
|
+
"(name + 1-line description, grouped by category). Call with `category` (e.g. " +
|
|
28
|
+
"\"browser\", \"fetch\") or `names` (exact tool names) to ACTIVATE those tools — " +
|
|
29
|
+
"they become callable starting on your next step. Use this whenever the tool you " +
|
|
30
|
+
"need (browser automation, HTTP fetch, web search, runtime delegation, voice, …) " +
|
|
31
|
+
"isn't in your current tool list.",
|
|
32
|
+
parameters: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
category: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description:
|
|
38
|
+
"Activate every not-loaded tool in this category (e.g. \"browser\", \"fetch\", \"search\").",
|
|
39
|
+
},
|
|
40
|
+
names: {
|
|
41
|
+
type: "array",
|
|
42
|
+
items: { type: "string" },
|
|
43
|
+
description:
|
|
44
|
+
"Exact tool names to activate, e.g. [\"browser_navigate\", \"browser_screenshot\"].",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
makeHandler: (ctx) => ({ category, names } = {}) => {
|
|
51
|
+
const session = ctx?.toolSession;
|
|
52
|
+
// No lazy session (full channels, or direct handler use in tests): every
|
|
53
|
+
// tool is already exposed, so there's nothing to discover or activate.
|
|
54
|
+
if (!session) {
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
loaded_all: true,
|
|
58
|
+
note: "En este canal todas las tools ya están cargadas; no hace falta discover_tools.",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const wantsActivate =
|
|
62
|
+
(Array.isArray(names) && names.length > 0) ||
|
|
63
|
+
(typeof category === "string" && category.trim() !== "");
|
|
64
|
+
if (!wantsActivate) return session.catalogResponse();
|
|
65
|
+
return session.activate({ names, category });
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { readVaultAgents, VAULT_DIR } from "../../../../core/parser.js";
|
|
4
4
|
import { addImportedAgent, ensureAgentDir } from "../../../../core/scaffold.js";
|
|
5
|
+
import { ensureAgentRuntimeDir } from "../../../../core/agent-memory.js";
|
|
5
6
|
import { confirmedProperty, projectMeta, resolveProject } from "../helpers.js";
|
|
6
7
|
|
|
7
8
|
export default {
|
|
@@ -35,6 +36,7 @@ export default {
|
|
|
35
36
|
const p = resolveProject(projects, project || "default");
|
|
36
37
|
addImportedAgent(p.path, slug);
|
|
37
38
|
ensureAgentDir(p.path, slug);
|
|
39
|
+
ensureAgentRuntimeDir(p, slug);
|
|
38
40
|
projects.rebuild(p.id);
|
|
39
41
|
|
|
40
42
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
2
|
import { resolveProject } from "../helpers.js";
|
|
3
|
+
import { agentMemoryPath, readAgentMemory } from "../../../../core/agent-memory.js";
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
name: "read_agent_memory",
|
|
@@ -21,8 +21,9 @@ export default {
|
|
|
21
21
|
},
|
|
22
22
|
makeHandler: ({ projects }) => ({ project, agent }) => {
|
|
23
23
|
const p = resolveProject(projects, project);
|
|
24
|
-
const file =
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const file = agentMemoryPath(p, agent);
|
|
25
|
+
const body = readAgentMemory(p, agent);
|
|
26
|
+
if (!body && !fs.existsSync(file)) return { error: `no memory.md for agent ${agent}` };
|
|
27
|
+
return { body, path: file };
|
|
27
28
|
},
|
|
28
29
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Super-agent: daemon-level action agent for Telegram, TUI, desktop, routines.
|
|
2
|
-
import {
|
|
2
|
+
import { createToolSession, buildLazyToolsBlock, makeToolHandlers } from "./super-agent-tools/index.js";
|
|
3
3
|
import { listSkills } from "./skills-loader.js";
|
|
4
4
|
import {
|
|
5
5
|
runAgent,
|
|
@@ -79,6 +79,15 @@ export async function runSuperAgent({
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Per-turn tool session. Lightweight channels (telegram/desktop/deck) start
|
|
83
|
+
// on the small "base" set and expand on demand via discover_tools; full
|
|
84
|
+
// channels (routine/api/web/code/terminal) get the whole registry up front.
|
|
85
|
+
// The session also enforces role gating ("*" = unrestricted, [] = none,
|
|
86
|
+
// array = allowlist) on BOTH the initial set and any later activation, so a
|
|
87
|
+
// limited sender can't discover its way past the gate.
|
|
88
|
+
// noTools callers (summarize/ask) get no session — text only.
|
|
89
|
+
const toolSession = noTools ? null : createToolSession(channel, { allowedTools });
|
|
90
|
+
|
|
82
91
|
const system = buildSuperAgentSystem({
|
|
83
92
|
globalConfig,
|
|
84
93
|
projects,
|
|
@@ -90,23 +99,12 @@ export async function runSuperAgent({
|
|
|
90
99
|
systemSuffix,
|
|
91
100
|
memoryBlock,
|
|
92
101
|
activeThreadsBlock,
|
|
102
|
+
// Compact "tools you can activate" block (names only, no schemas). Empty on
|
|
103
|
+
// full channels and tool-free callers, where it's omitted from the prompt.
|
|
104
|
+
lazyToolsBlock: buildLazyToolsBlock(toolSession),
|
|
93
105
|
});
|
|
94
106
|
|
|
95
|
-
|
|
96
|
-
// "core" set (~700 tokens) to fit cheap-tier TPM caps; routines get the
|
|
97
|
-
// full registry. The model can still call load_skill / read more on demand.
|
|
98
|
-
// noTools callers (summarize/ask) get an empty set — text only.
|
|
99
|
-
let toolSchemas = noTools ? [] : schemasForChannel(channel);
|
|
100
|
-
// Role gating: restrict the visible tools for limited senders (e.g. guests
|
|
101
|
-
// on Telegram). "*" = unrestricted; [] = no tools; array = allowlist.
|
|
102
|
-
if (allowedTools !== "*" && Array.isArray(allowedTools)) {
|
|
103
|
-
if (allowedTools.length === 0) {
|
|
104
|
-
toolSchemas = [];
|
|
105
|
-
} else {
|
|
106
|
-
const allow = new Set(allowedTools);
|
|
107
|
-
toolSchemas = toolSchemas.filter((t) => allow.has(t?.function?.name || t?.name));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
107
|
+
const toolSchemas = noTools ? [] : toolSession.initialSchemas;
|
|
110
108
|
|
|
111
109
|
return runAgent({
|
|
112
110
|
globalConfig,
|
|
@@ -116,7 +114,7 @@ export async function runSuperAgent({
|
|
|
116
114
|
overrideModel,
|
|
117
115
|
toolSchemas,
|
|
118
116
|
makeToolHandlers,
|
|
119
|
-
toolHandlerCtx: { projects, plugins, registries, globalConfig, channel },
|
|
117
|
+
toolHandlerCtx: { projects, plugins, registries, globalConfig, channel, toolSession },
|
|
120
118
|
onEvent,
|
|
121
119
|
signal,
|
|
122
120
|
onToken,
|
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { findApfRoot, readAgents, readVaultAgents, readVaultAgent, VAULT_DIR, SLUG_RE } from "../../../core/parser.js";
|
|
4
4
|
import { writeAgentFile, writeVaultAgentFile, removeVaultAgent, restoreVaultAgent, addImportedAgent, ensureAgentDir } from "../../../core/scaffold.js";
|
|
5
|
+
import { ensureAgentRuntimeDir, agentMemoryPath } from "../../../core/agent-memory.js";
|
|
5
6
|
import { http } from "../http.js";
|
|
6
7
|
|
|
7
8
|
// ── ANSI ──────────────────────────────────────────────────────────────────────
|
|
@@ -49,6 +50,7 @@ export async function cmdAgentAdd(args) {
|
|
|
49
50
|
|
|
50
51
|
writeAgentFile(root, slug, fields);
|
|
51
52
|
ensureAgentDir(root, slug);
|
|
53
|
+
ensureAgentRuntimeDir(root, slug);
|
|
52
54
|
await nudgeDaemon(root);
|
|
53
55
|
|
|
54
56
|
console.log(`Added agent ${slug}`);
|
|
@@ -207,10 +209,11 @@ export async function cmdAgentImport(args) {
|
|
|
207
209
|
addImportedAgent(root, slug);
|
|
208
210
|
console.log(`\n ${bold(slug)} imported from vault ${tag("↑ vault")}\n`);
|
|
209
211
|
console.log(gray(` definition: ${vaultPath}`));
|
|
210
|
-
console.log(gray(` memory: ${
|
|
212
|
+
console.log(gray(` memory: ${agentMemoryPath(root, slug)} (runtime-local)`));
|
|
211
213
|
console.log();
|
|
212
214
|
}
|
|
213
215
|
|
|
214
216
|
ensureAgentDir(root, slug);
|
|
217
|
+
ensureAgentRuntimeDir(root, slug);
|
|
215
218
|
await nudgeDaemon(root);
|
|
216
219
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
2
|
import { findApfRoot } from "../../../core/parser.js";
|
|
4
|
-
import {
|
|
3
|
+
import { agentMemoryPath, readAgentMemory, writeAgentMemory, ensureAgentRuntimeDir } from "../../../core/agent-memory.js";
|
|
5
4
|
import { http } from "../http.js";
|
|
6
5
|
|
|
7
6
|
function requireRoot() {
|
|
@@ -23,12 +22,11 @@ export async function cmdMemory(args) {
|
|
|
23
22
|
const slug = args._[0];
|
|
24
23
|
if (!slug) throw new Error("apx memory: missing <agent-slug>");
|
|
25
24
|
const root = requireRoot();
|
|
26
|
-
const memPath =
|
|
25
|
+
const memPath = agentMemoryPath(root, slug);
|
|
27
26
|
|
|
28
27
|
if (args.flags.replace) {
|
|
29
28
|
const newBody = readStdinSync();
|
|
30
|
-
|
|
31
|
-
fs.writeFileSync(memPath, newBody);
|
|
29
|
+
writeAgentMemory(root, slug, newBody);
|
|
32
30
|
await nudgeDaemon(root);
|
|
33
31
|
console.log(`replaced memory for ${slug} (${Buffer.byteLength(newBody)} bytes)`);
|
|
34
32
|
return;
|
|
@@ -36,23 +34,24 @@ export async function cmdMemory(args) {
|
|
|
36
34
|
|
|
37
35
|
if (args.flags.append && args.flags.append !== true) {
|
|
38
36
|
const note = String(args.flags.append);
|
|
39
|
-
|
|
40
|
-
let body =
|
|
37
|
+
ensureAgentRuntimeDir(root, slug);
|
|
38
|
+
let body = readAgentMemory(root, slug);
|
|
41
39
|
if (!/##\s+Recent context/i.test(body)) {
|
|
42
40
|
body += body.endsWith("\n") ? "\n## Recent context\n" : "\n\n## Recent context\n";
|
|
43
41
|
}
|
|
44
42
|
const today = new Date().toISOString().slice(0, 10);
|
|
45
43
|
body = body.replace(/(##\s+Recent context\s*\n)/i, `$1- ${today}: ${note}\n`);
|
|
46
|
-
|
|
44
|
+
writeAgentMemory(root, slug, body);
|
|
47
45
|
await nudgeDaemon(root);
|
|
48
46
|
console.log(`appended to ${slug} memory: ${note}`);
|
|
49
47
|
return;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
|
|
50
|
+
const body = readAgentMemory(root, slug);
|
|
51
|
+
if (!body && !fs.existsSync(memPath)) {
|
|
53
52
|
throw new Error(`no memory for "${slug}" — agent dir not yet created`);
|
|
54
53
|
}
|
|
55
|
-
process.stdout.write(
|
|
54
|
+
process.stdout.write(body);
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
function readStdinSync() {
|