hoomanjs 1.14.0 → 1.16.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/acp/utils/tool-kind.ts +15 -0
- package/src/cli.ts +1 -0
- package/src/configure/app.tsx +75 -0
- package/src/configure/types.ts +1 -0
- package/src/core/agent/index.ts +38 -15
- package/src/core/agents/definitions.ts +46 -0
- package/src/core/agents/index.ts +15 -0
- package/src/core/agents/registry.ts +108 -0
- package/src/core/agents/runner.ts +375 -0
- package/src/core/agents/tools.ts +100 -0
- package/src/core/approvals/allowed-tools.ts +29 -4
- package/src/core/config.ts +54 -0
- package/src/core/index.ts +6 -1
- package/src/core/prompts/agents/plan.md +35 -0
- package/src/core/prompts/agents/research.md +32 -0
- package/src/core/prompts/environment.ts +62 -0
- package/src/core/prompts/harness/behaviour.md +28 -0
- package/src/core/prompts/harness/communication.md +31 -0
- package/src/core/prompts/harness/engineering.md +29 -0
- package/src/core/prompts/harness/execution.md +29 -0
- package/src/core/prompts/harness/guardrails.md +28 -0
- package/src/core/prompts/index.ts +7 -3
- package/src/core/prompts/static/daemon.md +22 -0
- package/src/core/prompts/static/environment.md +15 -0
- package/src/core/prompts/static/filesystem.md +2 -2
- package/src/core/prompts/static/ltm.md +6 -6
- package/src/core/prompts/static/shell.md +2 -2
- package/src/core/prompts/static/skills.md +1 -1
- package/src/core/prompts/static/sleep.md +20 -0
- package/src/core/prompts/static/subagents.md +28 -0
- package/src/core/prompts/static/thinking.md +2 -2
- package/src/core/prompts/static/todo.md +3 -3
- package/src/core/prompts/static/wiki.md +1 -1
- package/src/core/prompts/system.ts +53 -1
- package/src/core/tools/index.ts +1 -0
- package/src/core/tools/sleep.ts +51 -0
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ const KNOWN_TOOL_KINDS = new Map<string, ToolKind>([
|
|
|
14
14
|
["search_files", "search"],
|
|
15
15
|
["get_file_info", "read"],
|
|
16
16
|
["shell", "execute"],
|
|
17
|
+
["sleep", "other"],
|
|
17
18
|
["fetch", "fetch"],
|
|
18
19
|
["wiki_list_files", "read"],
|
|
19
20
|
["wiki_read_file", "read"],
|
|
@@ -22,9 +23,23 @@ const KNOWN_TOOL_KINDS = new Map<string, ToolKind>([
|
|
|
22
23
|
["wiki_stats", "read"],
|
|
23
24
|
["wiki_search", "search"],
|
|
24
25
|
["think", "think"],
|
|
26
|
+
["run_agents", "other"],
|
|
25
27
|
["update_todos", "other"],
|
|
26
28
|
["get_current_time", "other"],
|
|
27
29
|
["convert_time", "other"],
|
|
30
|
+
["list_skills", "read"],
|
|
31
|
+
["search_skills", "search"],
|
|
32
|
+
["install_skill", "edit"],
|
|
33
|
+
["delete_skill", "edit"],
|
|
34
|
+
["store_memory", "edit"],
|
|
35
|
+
["search_memory", "search"],
|
|
36
|
+
["update_memory", "edit"],
|
|
37
|
+
["archive_memory", "edit"],
|
|
38
|
+
["list_mcp_servers", "read"],
|
|
39
|
+
["get_mcp_server", "read"],
|
|
40
|
+
["add_mcp_server", "edit"],
|
|
41
|
+
["update_mcp_server", "edit"],
|
|
42
|
+
["delete_mcp_server", "edit"],
|
|
28
43
|
]);
|
|
29
44
|
|
|
30
45
|
export { INTERNAL_ALWAYS_ALLOWED };
|
package/src/cli.ts
CHANGED
package/src/configure/app.tsx
CHANGED
|
@@ -46,6 +46,14 @@ import {
|
|
|
46
46
|
truncate,
|
|
47
47
|
} from "./utils.ts";
|
|
48
48
|
|
|
49
|
+
const PROMPT_LABELS: Record<keyof ConfigData["prompts"], string> = {
|
|
50
|
+
behaviour: "Behaviour",
|
|
51
|
+
communication: "Communication",
|
|
52
|
+
execution: "Execution",
|
|
53
|
+
engineering: "Engineering",
|
|
54
|
+
guardrails: "Guardrails",
|
|
55
|
+
};
|
|
56
|
+
|
|
49
57
|
export function ConfigureApp({
|
|
50
58
|
config,
|
|
51
59
|
mcpConfig,
|
|
@@ -131,6 +139,7 @@ export function ConfigureApp({
|
|
|
131
139
|
({
|
|
132
140
|
name: config.name,
|
|
133
141
|
llm: config.llm,
|
|
142
|
+
prompts: config.prompts,
|
|
134
143
|
tools: config.tools,
|
|
135
144
|
compaction: config.compaction,
|
|
136
145
|
}) satisfies ConfigData,
|
|
@@ -369,6 +378,10 @@ export function ConfigureApp({
|
|
|
369
378
|
};
|
|
370
379
|
|
|
371
380
|
const renderConfigMenu = () => {
|
|
381
|
+
const enabledPrompts = Object.values(configData.prompts).filter(
|
|
382
|
+
Boolean,
|
|
383
|
+
).length;
|
|
384
|
+
const totalPrompts = Object.keys(configData.prompts).length;
|
|
372
385
|
const items: MenuItem[] = [
|
|
373
386
|
{
|
|
374
387
|
label: `Name • ${configData.name}`,
|
|
@@ -431,6 +444,10 @@ export function ConfigureApp({
|
|
|
431
444
|
},
|
|
432
445
|
}),
|
|
433
446
|
},
|
|
447
|
+
{
|
|
448
|
+
label: `Prompts • ${enabledPrompts}/${totalPrompts} enabled`,
|
|
449
|
+
value: () => setScreen({ kind: "config-prompts" }),
|
|
450
|
+
},
|
|
434
451
|
{
|
|
435
452
|
label: `Todo tool • ${configData.tools.todo.enabled ? "Enabled" : "Disabled"}`,
|
|
436
453
|
value: () => {
|
|
@@ -499,6 +516,23 @@ export function ConfigureApp({
|
|
|
499
516
|
setScreen({ kind: "config" });
|
|
500
517
|
},
|
|
501
518
|
},
|
|
519
|
+
{
|
|
520
|
+
label: `Sleep tool • ${configData.tools.sleep.enabled ? "Enabled" : "Disabled"}`,
|
|
521
|
+
value: () => {
|
|
522
|
+
updateConfig(
|
|
523
|
+
{
|
|
524
|
+
tools: {
|
|
525
|
+
...config.tools,
|
|
526
|
+
sleep: {
|
|
527
|
+
enabled: !configData.tools.sleep.enabled,
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
`Sleep tool ${configData.tools.sleep.enabled ? "disabled" : "enabled"}.`,
|
|
532
|
+
);
|
|
533
|
+
setScreen({ kind: "config" });
|
|
534
|
+
},
|
|
535
|
+
},
|
|
502
536
|
{
|
|
503
537
|
label: `Long-term memory • ${configData.tools.ltm.enabled ? "Enabled" : "Disabled"} • ${configData.tools.ltm.chroma.collection.memory}`,
|
|
504
538
|
value: () => setScreen({ kind: "config-ltm" }),
|
|
@@ -636,6 +670,45 @@ export function ConfigureApp({
|
|
|
636
670
|
);
|
|
637
671
|
};
|
|
638
672
|
|
|
673
|
+
const renderPromptsConfigMenu = () => {
|
|
674
|
+
const promptKeys = Object.keys(
|
|
675
|
+
PROMPT_LABELS,
|
|
676
|
+
) as (keyof ConfigData["prompts"])[];
|
|
677
|
+
const items: MenuItem[] = [
|
|
678
|
+
...promptKeys.map((key) => {
|
|
679
|
+
const enabled = configData.prompts[key];
|
|
680
|
+
const label = PROMPT_LABELS[key];
|
|
681
|
+
return {
|
|
682
|
+
label: `${label} • ${enabled ? "Enabled" : "Disabled"}`,
|
|
683
|
+
value: () => {
|
|
684
|
+
updateConfig(
|
|
685
|
+
{
|
|
686
|
+
prompts: {
|
|
687
|
+
...config.prompts,
|
|
688
|
+
[key]: !enabled,
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
`${label} prompt ${enabled ? "disabled" : "enabled"}.`,
|
|
692
|
+
);
|
|
693
|
+
setScreen({ kind: "config-prompts" });
|
|
694
|
+
},
|
|
695
|
+
};
|
|
696
|
+
}),
|
|
697
|
+
{
|
|
698
|
+
label: "Back",
|
|
699
|
+
value: () => setScreen({ kind: "config" }),
|
|
700
|
+
},
|
|
701
|
+
];
|
|
702
|
+
|
|
703
|
+
return (
|
|
704
|
+
<MenuScreen
|
|
705
|
+
title="Prompts"
|
|
706
|
+
description="Choose which bundled harness prompt sections are included in future sessions."
|
|
707
|
+
items={items}
|
|
708
|
+
/>
|
|
709
|
+
);
|
|
710
|
+
};
|
|
711
|
+
|
|
639
712
|
const renderLtmConfigMenu = () => {
|
|
640
713
|
const items: MenuItem[] = [
|
|
641
714
|
{
|
|
@@ -1096,6 +1169,8 @@ export function ConfigureApp({
|
|
|
1096
1169
|
return renderConfigMenu();
|
|
1097
1170
|
case "config-provider":
|
|
1098
1171
|
return renderProviderMenu();
|
|
1172
|
+
case "config-prompts":
|
|
1173
|
+
return renderPromptsConfigMenu();
|
|
1099
1174
|
case "config-ltm":
|
|
1100
1175
|
return renderLtmConfigMenu();
|
|
1101
1176
|
case "config-wiki":
|
package/src/configure/types.ts
CHANGED
package/src/core/agent/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Agent, BeforeInvocationEvent } from "@strands-agents/sdk";
|
|
2
|
+
import type { Tool } from "@strands-agents/sdk";
|
|
2
3
|
import type { Config } from "../config.ts";
|
|
3
4
|
import { modelProviders } from "../models";
|
|
4
5
|
import {
|
|
@@ -14,10 +15,15 @@ import {
|
|
|
14
15
|
createLongTermMemoryTools,
|
|
15
16
|
} from "../memory";
|
|
16
17
|
import { createSkillsTools, type Registry } from "../skills";
|
|
18
|
+
import {
|
|
19
|
+
createRunAgentsTools,
|
|
20
|
+
loadBuiltInAgentDefinitions,
|
|
21
|
+
} from "../agents/index.ts";
|
|
17
22
|
import {
|
|
18
23
|
createTodoTools,
|
|
19
24
|
createFetchTools,
|
|
20
25
|
createFilesystemTools,
|
|
26
|
+
createSleepTools,
|
|
21
27
|
createShellTools,
|
|
22
28
|
createThinkingTools,
|
|
23
29
|
createTimeTools,
|
|
@@ -49,7 +55,7 @@ export async function create(
|
|
|
49
55
|
const skills = config.tools.skills.enabled
|
|
50
56
|
? (await createSkillsPrompt(registry)).content
|
|
51
57
|
: "";
|
|
52
|
-
const
|
|
58
|
+
const prefixed = config.tools.mcp.enabled
|
|
53
59
|
? await mcp.manager.listPrefixedTools()
|
|
54
60
|
: [];
|
|
55
61
|
const append = config.tools.mcp.enabled
|
|
@@ -58,27 +64,44 @@ export async function create(
|
|
|
58
64
|
const prompt = [system.content, meta.systemPrompt, ...append, skills]
|
|
59
65
|
.filter((x) => !!x)
|
|
60
66
|
.join(SECTION_BREAK);
|
|
67
|
+
const model = llm.create(config.llm.model, config.llm.params);
|
|
68
|
+
const tools: Tool[] = [
|
|
69
|
+
...createTimeTools(),
|
|
70
|
+
...(config.tools.sleep.enabled ? createSleepTools() : []),
|
|
71
|
+
...(config.tools.todo.enabled ? createTodoTools() : []),
|
|
72
|
+
...(config.tools.fetch.enabled ? createFetchTools() : []),
|
|
73
|
+
...(ltm ? createLongTermMemoryTools(ltm) : []),
|
|
74
|
+
...(config.tools.filesystem.enabled ? createFilesystemTools() : []),
|
|
75
|
+
...(config.tools.shell.enabled ? createShellTools() : []),
|
|
76
|
+
...(config.tools.wiki.enabled ? createWikiTools(config) : []),
|
|
77
|
+
...(config.tools.mcp.enabled ? createMcpTools(mcp.config) : []),
|
|
78
|
+
...(config.tools.skills.enabled ? createSkillsTools(registry) : []),
|
|
79
|
+
...createThinkingTools(),
|
|
80
|
+
...prefixed,
|
|
81
|
+
];
|
|
82
|
+
if (config.tools.agents.enabled) {
|
|
83
|
+
const definitions = loadBuiltInAgentDefinitions(config, {
|
|
84
|
+
knownTools: tools.map((entry) => entry.name),
|
|
85
|
+
});
|
|
86
|
+
tools.push(
|
|
87
|
+
...createRunAgentsTools({
|
|
88
|
+
parent: config.name,
|
|
89
|
+
definitions,
|
|
90
|
+
tools,
|
|
91
|
+
createModel: () => llm.create(config.llm.model, config.llm.params),
|
|
92
|
+
defaultConcurrency: config.tools.agents.concurrency,
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
61
96
|
const agent = new Agent({
|
|
62
97
|
name: config.name,
|
|
63
98
|
systemPrompt: prompt,
|
|
64
|
-
model
|
|
99
|
+
model,
|
|
65
100
|
appState: {
|
|
66
101
|
...(userId ? { userId } : {}),
|
|
67
102
|
...(sessionId ? { sessionId } : {}),
|
|
68
103
|
},
|
|
69
|
-
tools
|
|
70
|
-
...createTimeTools(),
|
|
71
|
-
...(config.tools.todo.enabled ? createTodoTools() : []),
|
|
72
|
-
...(config.tools.fetch.enabled ? createFetchTools() : []),
|
|
73
|
-
...(ltm ? createLongTermMemoryTools(ltm) : []),
|
|
74
|
-
...(config.tools.filesystem.enabled ? createFilesystemTools() : []),
|
|
75
|
-
...(config.tools.shell.enabled ? createShellTools() : []),
|
|
76
|
-
...(config.tools.wiki.enabled ? createWikiTools(config) : []),
|
|
77
|
-
...(config.tools.mcp.enabled ? createMcpTools(mcp.config) : []),
|
|
78
|
-
...(config.tools.skills.enabled ? createSkillsTools(registry) : []),
|
|
79
|
-
...createThinkingTools(),
|
|
80
|
-
...tools,
|
|
81
|
-
],
|
|
104
|
+
tools,
|
|
82
105
|
printer: print,
|
|
83
106
|
...stm,
|
|
84
107
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const BUILTIN_AGENT_KINDS = ["research", "plan"] as const;
|
|
2
|
+
|
|
3
|
+
export type AgentKind = (typeof BUILTIN_AGENT_KINDS)[number];
|
|
4
|
+
|
|
5
|
+
export type AgentConfig = {
|
|
6
|
+
id: AgentKind;
|
|
7
|
+
instructions: string;
|
|
8
|
+
description: string;
|
|
9
|
+
tools: readonly string[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type AgentDefinition = AgentConfig & {
|
|
13
|
+
instructionsText: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const BUILTIN_AGENT_CONFIGS: readonly AgentConfig[] = [
|
|
17
|
+
{
|
|
18
|
+
id: "research",
|
|
19
|
+
instructions: "research.md",
|
|
20
|
+
description: "Investigates sources and context before the parent acts.",
|
|
21
|
+
tools: [
|
|
22
|
+
"read_file",
|
|
23
|
+
"read_multiple_files",
|
|
24
|
+
"list_directory",
|
|
25
|
+
"directory_tree",
|
|
26
|
+
"search_files",
|
|
27
|
+
"get_file_info",
|
|
28
|
+
"fetch",
|
|
29
|
+
"think",
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "plan",
|
|
34
|
+
instructions: "plan.md",
|
|
35
|
+
description: "Produces plans, tradeoffs, risks, and validation steps.",
|
|
36
|
+
tools: [
|
|
37
|
+
"read_file",
|
|
38
|
+
"read_multiple_files",
|
|
39
|
+
"list_directory",
|
|
40
|
+
"directory_tree",
|
|
41
|
+
"search_files",
|
|
42
|
+
"get_file_info",
|
|
43
|
+
"think",
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
BUILTIN_AGENT_CONFIGS,
|
|
3
|
+
BUILTIN_AGENT_KINDS,
|
|
4
|
+
type AgentConfig,
|
|
5
|
+
type AgentDefinition,
|
|
6
|
+
type AgentKind,
|
|
7
|
+
} from "./definitions.ts";
|
|
8
|
+
export { loadBuiltInAgentDefinitions } from "./registry.ts";
|
|
9
|
+
export {
|
|
10
|
+
runAgentJobs,
|
|
11
|
+
type AgentJob,
|
|
12
|
+
type AgentJobResult,
|
|
13
|
+
type RunAgentJobsResult,
|
|
14
|
+
} from "./runner.ts";
|
|
15
|
+
export { RUN_AGENTS_TOOL_NAME, createRunAgentsTools } from "./tools.ts";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { compile } from "handlebars";
|
|
5
|
+
import type { Config } from "../config.ts";
|
|
6
|
+
import { getEnvironmentPromptContext } from "../prompts/environment.ts";
|
|
7
|
+
import {
|
|
8
|
+
BUILTIN_AGENT_CONFIGS,
|
|
9
|
+
type AgentConfig,
|
|
10
|
+
type AgentDefinition,
|
|
11
|
+
} from "./definitions.ts";
|
|
12
|
+
|
|
13
|
+
function promptsDir(): string {
|
|
14
|
+
return join(dirname(fileURLToPath(import.meta.url)), "../prompts/agents");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function validateConfigs(configs: readonly AgentConfig[]): void {
|
|
18
|
+
const seen = new Set<string>();
|
|
19
|
+
for (const config of configs) {
|
|
20
|
+
if (!config.id.trim()) {
|
|
21
|
+
throw new Error("Agent config id cannot be empty.");
|
|
22
|
+
}
|
|
23
|
+
if (seen.has(config.id)) {
|
|
24
|
+
throw new Error(`Duplicate agent config id: '${config.id}'.`);
|
|
25
|
+
}
|
|
26
|
+
seen.add(config.id);
|
|
27
|
+
if (!config.instructions.trim()) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Agent '${config.id}' instructions file cannot be empty.`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (!config.description.trim()) {
|
|
33
|
+
throw new Error(`Agent '${config.id}' description cannot be empty.`);
|
|
34
|
+
}
|
|
35
|
+
if (!Array.isArray(config.tools) || config.tools.length === 0) {
|
|
36
|
+
throw new Error(`Agent '${config.id}' must declare at least one tool.`);
|
|
37
|
+
}
|
|
38
|
+
for (const toolName of config.tools) {
|
|
39
|
+
if (!toolName.trim()) {
|
|
40
|
+
throw new Error(`Agent '${config.id}' has an empty tool name.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function assertKnownTools(
|
|
47
|
+
definitions: readonly AgentDefinition[],
|
|
48
|
+
knownTools: readonly string[],
|
|
49
|
+
): void {
|
|
50
|
+
const known = new Set(knownTools);
|
|
51
|
+
for (const definition of definitions) {
|
|
52
|
+
for (const toolName of definition.tools) {
|
|
53
|
+
if (!known.has(toolName)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Agent '${definition.id}' references unknown tool '${toolName}'.`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function context(config: Config): Record<string, unknown> {
|
|
63
|
+
return {
|
|
64
|
+
name: config.name,
|
|
65
|
+
llm: config.llm,
|
|
66
|
+
environment: getEnvironmentPromptContext(),
|
|
67
|
+
ltm: config.tools.ltm,
|
|
68
|
+
wiki: config.tools.wiki,
|
|
69
|
+
compaction: config.compaction,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function loadBuiltInAgentDefinitions(
|
|
74
|
+
config: Config,
|
|
75
|
+
options?: { knownTools?: readonly string[] },
|
|
76
|
+
): AgentDefinition[] {
|
|
77
|
+
validateConfigs(BUILTIN_AGENT_CONFIGS);
|
|
78
|
+
const dir = promptsDir();
|
|
79
|
+
const definitions = BUILTIN_AGENT_CONFIGS.map((entry) => {
|
|
80
|
+
const fullPath = join(dir, entry.instructions);
|
|
81
|
+
if (!existsSync(fullPath)) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Agent '${entry.id}' instructions file not found: ${entry.instructions}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const raw = readFileSync(fullPath, "utf8").trim();
|
|
87
|
+
if (!raw) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Agent '${entry.id}' instructions file is empty: ${entry.instructions}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const template = compile(raw);
|
|
93
|
+
const instructionsText = template(context(config)).trim();
|
|
94
|
+
if (!instructionsText) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Agent '${entry.id}' instructions rendered to empty content.`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
...entry,
|
|
101
|
+
instructionsText,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
if (options?.knownTools) {
|
|
105
|
+
assertKnownTools(definitions, options.knownTools);
|
|
106
|
+
}
|
|
107
|
+
return definitions;
|
|
108
|
+
}
|