@compilr-dev/agents 0.2.0 → 0.3.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/dist/agent.d.ts +8 -0
- package/dist/agent.js +187 -121
- package/dist/anchors/manager.d.ts +34 -0
- package/dist/anchors/manager.js +86 -0
- package/dist/anchors/types.d.ts +29 -0
- package/dist/skills/index.js +2 -179
- package/dist/tools/builtin/ask-user-simple.d.ts +64 -0
- package/dist/tools/builtin/ask-user-simple.js +149 -0
- package/dist/tools/builtin/ask-user.d.ts +85 -0
- package/dist/tools/builtin/ask-user.js +195 -0
- package/dist/tools/builtin/backlog.d.ts +121 -0
- package/dist/tools/builtin/backlog.js +368 -0
- package/dist/tools/builtin/bash.js +180 -13
- package/dist/tools/builtin/index.d.ts +11 -1
- package/dist/tools/builtin/index.js +16 -0
- package/dist/tools/builtin/task.d.ts +14 -4
- package/dist/tools/builtin/task.js +9 -9
- package/dist/tools/define.d.ts +7 -0
- package/dist/tools/define.js +1 -0
- package/dist/tools/registry.d.ts +3 -2
- package/dist/tools/registry.js +19 -6
- package/dist/tools/types.d.ts +29 -2
- package/package.json +4 -4
package/dist/skills/index.js
CHANGED
|
@@ -773,185 +773,8 @@ Create the directory if it doesn't exist.
|
|
|
773
773
|
✓ User has reviewed the note`,
|
|
774
774
|
tags: ['documentation', 'session'],
|
|
775
775
|
}),
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
description: 'Implement a backlog item end-to-end',
|
|
779
|
-
tags: ['implementation', 'coding'],
|
|
780
|
-
prompt: `You are in BUILD MODE. Implement the specified backlog item.
|
|
781
|
-
|
|
782
|
-
## ITEM TO IMPLEMENT
|
|
783
|
-
- **ID:** {{item_id}}
|
|
784
|
-
- **Title:** {{item_title}}
|
|
785
|
-
- **Type:** {{item_type}}
|
|
786
|
-
- **Priority:** {{item_priority}}
|
|
787
|
-
- **Description:** {{item_description}}
|
|
788
|
-
|
|
789
|
-
## BEFORE STARTING
|
|
790
|
-
|
|
791
|
-
1. Show the item details to the user in a clear format
|
|
792
|
-
2. Use ask_user_simple to confirm: "Proceed with implementation?"
|
|
793
|
-
- Options: "Yes, let's build it", "No, pick a different item", "Cancel"
|
|
794
|
-
3. If there are dependency warnings, mention them and ask if user wants to proceed anyway
|
|
795
|
-
|
|
796
|
-
## CONTEXT TO READ
|
|
797
|
-
|
|
798
|
-
Before implementing, read these files for context:
|
|
799
|
-
- **PRD.md** (if exists): Project vision and requirements
|
|
800
|
-
- **CLAUDE.md**: Coding standards and conventions
|
|
801
|
-
- **Existing code**: Understand patterns already in use
|
|
802
|
-
|
|
803
|
-
## IMPLEMENTATION WORKFLOW
|
|
804
|
-
|
|
805
|
-
### Phase 1: Plan
|
|
806
|
-
1. Use todo_write to create implementation checklist:
|
|
807
|
-
- Break down the item into concrete tasks
|
|
808
|
-
- Identify files to create or modify
|
|
809
|
-
- Note any edge cases to handle
|
|
810
|
-
2. Update backlog status to 🚧 using backlog_write
|
|
811
|
-
|
|
812
|
-
### Phase 2: Implement
|
|
813
|
-
1. Write code following project conventions from CLAUDE.md
|
|
814
|
-
2. Add tests if the project has a test framework
|
|
815
|
-
3. Keep changes focused on the backlog item scope
|
|
816
|
-
4. Use todo_write to track progress through tasks
|
|
817
|
-
|
|
818
|
-
### Phase 3: Verify
|
|
819
|
-
1. Run tests with run_tests tool
|
|
820
|
-
2. Run lint with run_lint tool
|
|
821
|
-
3. If tests or lint fail:
|
|
822
|
-
- Analyze the error message
|
|
823
|
-
- Fix the issue
|
|
824
|
-
- Re-run verification
|
|
825
|
-
- Repeat up to 3 times
|
|
826
|
-
4. If still failing after 3 attempts:
|
|
827
|
-
- Report the issue to user
|
|
828
|
-
- Keep status as 🚧
|
|
829
|
-
- Ask for guidance
|
|
830
|
-
|
|
831
|
-
### Phase 4: Complete
|
|
832
|
-
1. Update backlog status to ✅ using backlog_write
|
|
833
|
-
2. Create git commit with message format:
|
|
834
|
-
- feat({{item_id}}): {{item_title}} - for features
|
|
835
|
-
- fix({{item_id}}): {{item_title}} - for bugs
|
|
836
|
-
- chore({{item_id}}): {{item_title}} - for chores
|
|
837
|
-
3. Update backlog with the commit SHA
|
|
838
|
-
4. Clear todos with todo_write
|
|
839
|
-
5. Summarize what was implemented
|
|
840
|
-
|
|
841
|
-
## RULES
|
|
842
|
-
|
|
843
|
-
- Follow coding standards from CLAUDE.md strictly
|
|
844
|
-
- Keep commits atomic - one backlog item per commit
|
|
845
|
-
- Ask user via ask_user_simple if you hit blockers
|
|
846
|
-
- Don't over-engineer - implement exactly what the item describes
|
|
847
|
-
- Don't add features beyond what was requested
|
|
848
|
-
- Use todo_write throughout to show progress
|
|
849
|
-
- Always run tests before marking complete`,
|
|
850
|
-
}),
|
|
851
|
-
defineSkill({
|
|
852
|
-
name: 'scaffold',
|
|
853
|
-
description: 'Create project foundation based on tech stack',
|
|
854
|
-
tags: ['setup', 'foundation', 'scaffolding'],
|
|
855
|
-
prompt: `You are creating the PROJECT SCAFFOLD (foundation).
|
|
856
|
-
|
|
857
|
-
## PURPOSE
|
|
858
|
-
|
|
859
|
-
Create the base project structure that features will be built on top of.
|
|
860
|
-
This is the skeleton that makes feature implementation possible.
|
|
861
|
-
|
|
862
|
-
## CONTEXT TO READ
|
|
863
|
-
|
|
864
|
-
First, read these files to understand what to build:
|
|
865
|
-
- **CLAUDE.md**: Tech stack, coding standards, project type
|
|
866
|
-
- **PRD.md** (if exists): Project vision and requirements
|
|
867
|
-
- **Existing files**: What already exists (if anything)
|
|
868
|
-
|
|
869
|
-
## BEFORE STARTING
|
|
870
|
-
|
|
871
|
-
1. Summarize the detected/specified tech stack
|
|
872
|
-
2. Use ask_user_simple to confirm: "Create project scaffold with this stack?"
|
|
873
|
-
- Options: "Yes, create it", "No, let me specify", "Cancel"
|
|
874
|
-
3. If user wants to specify, ask about tech stack preferences
|
|
875
|
-
|
|
876
|
-
## SCAFFOLD BY PROJECT TYPE
|
|
877
|
-
|
|
878
|
-
### Web Application (React/Vue/Svelte)
|
|
879
|
-
|
|
880
|
-
Create:
|
|
881
|
-
- \`src/\` folder structure:
|
|
882
|
-
- \`src/components/\` - Reusable components
|
|
883
|
-
- \`src/pages/\` or \`src/routes/\` - Page components
|
|
884
|
-
- \`src/lib/\` or \`src/utils/\` - Utility functions
|
|
885
|
-
- \`src/styles/\` - Global styles
|
|
886
|
-
- \`package.json\` with dependencies
|
|
887
|
-
- Build config (\`vite.config.ts\`, \`next.config.js\`, etc.)
|
|
888
|
-
- \`index.html\` entry point (if applicable)
|
|
889
|
-
- Basic App component with routing setup
|
|
890
|
-
- CSS/Tailwind configuration
|
|
891
|
-
- \`.gitignore\`
|
|
892
|
-
- \`README.md\` with setup instructions
|
|
893
|
-
|
|
894
|
-
### API / Backend (Node/Python/Go)
|
|
895
|
-
|
|
896
|
-
Create:
|
|
897
|
-
- \`src/\` folder structure:
|
|
898
|
-
- \`src/routes/\` or \`src/api/\` - API endpoints
|
|
899
|
-
- \`src/services/\` - Business logic
|
|
900
|
-
- \`src/models/\` - Data models
|
|
901
|
-
- \`src/utils/\` - Utilities
|
|
902
|
-
- \`package.json\` / \`requirements.txt\` / \`go.mod\`
|
|
903
|
-
- Entry point (\`src/index.ts\`, \`main.py\`, \`main.go\`)
|
|
904
|
-
- Basic server setup (Express, FastAPI, Gin, etc.)
|
|
905
|
-
- Health check endpoint (\`GET /health\`)
|
|
906
|
-
- Environment config (\`.env.example\`)
|
|
907
|
-
- \`.gitignore\`
|
|
908
|
-
- \`README.md\` with setup instructions
|
|
909
|
-
|
|
910
|
-
### CLI Tool (Node/Python/Rust)
|
|
911
|
-
|
|
912
|
-
Create:
|
|
913
|
-
- \`src/\` folder structure:
|
|
914
|
-
- \`src/commands/\` - Command handlers
|
|
915
|
-
- \`src/utils/\` - Utilities
|
|
916
|
-
- \`package.json\` with \`bin\` entry / \`setup.py\` / \`Cargo.toml\`
|
|
917
|
-
- Entry point with argument parsing
|
|
918
|
-
- Basic command structure (help, version)
|
|
919
|
-
- \`.gitignore\`
|
|
920
|
-
- \`README.md\` with usage instructions
|
|
921
|
-
|
|
922
|
-
### Full-Stack Application
|
|
923
|
-
|
|
924
|
-
Create both frontend and backend structures:
|
|
925
|
-
- \`frontend/\` or \`client/\` - Web app scaffold
|
|
926
|
-
- \`backend/\` or \`server/\` - API scaffold
|
|
927
|
-
- Root \`package.json\` with workspace config (if monorepo)
|
|
928
|
-
- \`docker-compose.yml\` (optional)
|
|
929
|
-
- \`.gitignore\`
|
|
930
|
-
- \`README.md\` with setup instructions
|
|
931
|
-
|
|
932
|
-
## POST-SCAFFOLD STEPS
|
|
933
|
-
|
|
934
|
-
1. Install dependencies:
|
|
935
|
-
- \`npm install\` / \`pip install -r requirements.txt\` / etc.
|
|
936
|
-
2. Run build to verify:
|
|
937
|
-
- \`npm run build\` / equivalent
|
|
938
|
-
3. Run lint to verify:
|
|
939
|
-
- \`npm run lint\` / equivalent
|
|
940
|
-
4. Create initial git commit:
|
|
941
|
-
- \`chore: initial project scaffold\`
|
|
942
|
-
5. Update backlog:
|
|
943
|
-
- Mark scaffold CHORE as ✅ (if exists)
|
|
944
|
-
|
|
945
|
-
## RULES
|
|
946
|
-
|
|
947
|
-
- Follow conventions from CLAUDE.md
|
|
948
|
-
- Use modern, widely-adopted patterns
|
|
949
|
-
- Keep it minimal - only what's needed to start
|
|
950
|
-
- Don't add features - just structure
|
|
951
|
-
- Ensure the project builds and lints clean
|
|
952
|
-
- Add helpful comments in config files
|
|
953
|
-
- Include TypeScript/type hints where applicable`,
|
|
954
|
-
}),
|
|
776
|
+
// NOTE: 'build' and 'scaffold' skills moved to @compilr-dev/agents-coding
|
|
777
|
+
// because they depend on coding-specific tools (run_tests, run_lint, detect_project)
|
|
955
778
|
];
|
|
956
779
|
/**
|
|
957
780
|
* Default skill registry with built-in skills
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask User Simple Tool - Single question with simple string options
|
|
3
|
+
*
|
|
4
|
+
* A simplified version of ask_user for single questions with string options.
|
|
5
|
+
* Preferred over ask_user when you only need to ask one simple question.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Single question
|
|
9
|
+
* - Simple string options (no value/label distinction)
|
|
10
|
+
* - Default value support
|
|
11
|
+
* - Factory function for custom implementations
|
|
12
|
+
*/
|
|
13
|
+
import type { Tool } from '../types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Input parameters for ask_user_simple tool
|
|
16
|
+
*/
|
|
17
|
+
export interface AskUserSimpleInput {
|
|
18
|
+
/** The question to ask */
|
|
19
|
+
question: string;
|
|
20
|
+
/** Simple string options to choose from */
|
|
21
|
+
options: string[];
|
|
22
|
+
/** Default value if user skips (optional) */
|
|
23
|
+
default?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Result from ask_user_simple tool
|
|
27
|
+
*/
|
|
28
|
+
export interface AskUserSimpleResult {
|
|
29
|
+
/** The selected answer */
|
|
30
|
+
answer: string;
|
|
31
|
+
/** Whether the default was used */
|
|
32
|
+
usedDefault?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Options for creating custom ask_user_simple tool
|
|
36
|
+
*/
|
|
37
|
+
export interface AskUserSimpleToolOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Custom handler for asking the question.
|
|
40
|
+
* If not provided, uses readline-based implementation.
|
|
41
|
+
*/
|
|
42
|
+
onAsk?: (question: string, options: string[], defaultValue?: string) => Promise<AskUserSimpleResult>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Default ask_user_simple tool using readline for basic CLI interaction.
|
|
46
|
+
* Use createAskUserSimpleTool() for custom implementations.
|
|
47
|
+
*/
|
|
48
|
+
export declare const askUserSimpleTool: Tool<AskUserSimpleInput>;
|
|
49
|
+
/**
|
|
50
|
+
* Create a custom ask_user_simple tool with your own UI implementation.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const customAskSimple = createAskUserSimpleTool({
|
|
55
|
+
* onAsk: async (question, options, defaultValue) => {
|
|
56
|
+
* // Show fancy UI overlay
|
|
57
|
+
* const overlay = new AskUserSimpleOverlay({ question, options, defaultValue });
|
|
58
|
+
* return await ui.showOverlay(overlay);
|
|
59
|
+
* }
|
|
60
|
+
* });
|
|
61
|
+
* agent.registerTool(customAskSimple);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function createAskUserSimpleTool(options?: AskUserSimpleToolOptions): Tool<AskUserSimpleInput>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask User Simple Tool - Single question with simple string options
|
|
3
|
+
*
|
|
4
|
+
* A simplified version of ask_user for single questions with string options.
|
|
5
|
+
* Preferred over ask_user when you only need to ask one simple question.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Single question
|
|
9
|
+
* - Simple string options (no value/label distinction)
|
|
10
|
+
* - Default value support
|
|
11
|
+
* - Factory function for custom implementations
|
|
12
|
+
*/
|
|
13
|
+
/* eslint-disable no-console -- Intentional console output for fallback CLI prompts */
|
|
14
|
+
import * as readline from 'readline';
|
|
15
|
+
import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Default Implementation (readline-based)
|
|
18
|
+
// =============================================================================
|
|
19
|
+
async function askSimpleWithReadline(question, options, defaultValue) {
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout,
|
|
23
|
+
});
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
// Print question and options
|
|
26
|
+
console.log(`\n${question}`);
|
|
27
|
+
options.forEach((opt, i) => {
|
|
28
|
+
console.log(` ${String(i + 1)}. ${opt}`);
|
|
29
|
+
});
|
|
30
|
+
if (defaultValue) {
|
|
31
|
+
console.log(` (Press Enter for default: ${defaultValue})`);
|
|
32
|
+
}
|
|
33
|
+
rl.question('Choice: ', (answer) => {
|
|
34
|
+
rl.close();
|
|
35
|
+
const trimmed = answer.trim();
|
|
36
|
+
// Empty input - use default or first option
|
|
37
|
+
if (!trimmed) {
|
|
38
|
+
if (defaultValue) {
|
|
39
|
+
resolve({ answer: defaultValue, usedDefault: true });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
resolve({ answer: options[0], usedDefault: true });
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Try to parse as number
|
|
47
|
+
const idx = parseInt(trimmed, 10) - 1;
|
|
48
|
+
if (idx >= 0 && idx < options.length) {
|
|
49
|
+
resolve({ answer: options[idx] });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Try to match option text (case-insensitive)
|
|
53
|
+
const lowerInput = trimmed.toLowerCase();
|
|
54
|
+
const matched = options.find((opt) => opt.toLowerCase() === lowerInput);
|
|
55
|
+
if (matched) {
|
|
56
|
+
resolve({ answer: matched });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// No match - use default or first option
|
|
60
|
+
if (defaultValue) {
|
|
61
|
+
resolve({ answer: defaultValue, usedDefault: true });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
resolve({ answer: options[0], usedDefault: true });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Tool Definition
|
|
71
|
+
// =============================================================================
|
|
72
|
+
/**
|
|
73
|
+
* Default ask_user_simple tool using readline for basic CLI interaction.
|
|
74
|
+
* Use createAskUserSimpleTool() for custom implementations.
|
|
75
|
+
*/
|
|
76
|
+
export const askUserSimpleTool = defineTool({
|
|
77
|
+
name: 'ask_user_simple',
|
|
78
|
+
description: 'Ask a single simple question with string options. ' +
|
|
79
|
+
'Use this instead of ask_user when you only need one question. ' +
|
|
80
|
+
'Provide 2-4 clear, concise options. ' +
|
|
81
|
+
'The user can select by number or by typing the option text.',
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
question: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
description: 'The question to ask the user',
|
|
88
|
+
},
|
|
89
|
+
options: {
|
|
90
|
+
type: 'array',
|
|
91
|
+
description: 'Available options (2-4 options)',
|
|
92
|
+
minItems: 2,
|
|
93
|
+
maxItems: 4,
|
|
94
|
+
items: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
default: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
description: 'Default value if user skips',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
required: ['question', 'options'],
|
|
104
|
+
},
|
|
105
|
+
execute: async (input) => {
|
|
106
|
+
try {
|
|
107
|
+
const result = await askSimpleWithReadline(input.question, input.options, input.default);
|
|
108
|
+
return createSuccessResult(result);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
// =============================================================================
|
|
116
|
+
// Factory Function
|
|
117
|
+
// =============================================================================
|
|
118
|
+
/**
|
|
119
|
+
* Create a custom ask_user_simple tool with your own UI implementation.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const customAskSimple = createAskUserSimpleTool({
|
|
124
|
+
* onAsk: async (question, options, defaultValue) => {
|
|
125
|
+
* // Show fancy UI overlay
|
|
126
|
+
* const overlay = new AskUserSimpleOverlay({ question, options, defaultValue });
|
|
127
|
+
* return await ui.showOverlay(overlay);
|
|
128
|
+
* }
|
|
129
|
+
* });
|
|
130
|
+
* agent.registerTool(customAskSimple);
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function createAskUserSimpleTool(options = {}) {
|
|
134
|
+
const handler = options.onAsk ?? askSimpleWithReadline;
|
|
135
|
+
return defineTool({
|
|
136
|
+
name: 'ask_user_simple',
|
|
137
|
+
description: askUserSimpleTool.definition.description,
|
|
138
|
+
inputSchema: askUserSimpleTool.definition.inputSchema,
|
|
139
|
+
execute: async (input) => {
|
|
140
|
+
try {
|
|
141
|
+
const result = await handler(input.question, input.options, input.default);
|
|
142
|
+
return createSuccessResult(result);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask User Tool - Gather input from user via questions with options
|
|
3
|
+
*
|
|
4
|
+
* This tool allows the agent to ask the user questions with predefined options.
|
|
5
|
+
* The default implementation uses Node.js readline for basic CLI interaction.
|
|
6
|
+
* Consumers (like CLI apps) can override with custom UI implementations.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Multiple questions in a single call
|
|
10
|
+
* - Options with labels, values, and descriptions
|
|
11
|
+
* - Multi-select support
|
|
12
|
+
* - Factory function for custom implementations
|
|
13
|
+
*/
|
|
14
|
+
import type { Tool } from '../types.js';
|
|
15
|
+
/**
|
|
16
|
+
* A single option for a question
|
|
17
|
+
*/
|
|
18
|
+
export interface AskUserOption {
|
|
19
|
+
/** Display text for the option */
|
|
20
|
+
label: string;
|
|
21
|
+
/** Value returned when this option is selected */
|
|
22
|
+
value: string;
|
|
23
|
+
/** Optional description/explanation */
|
|
24
|
+
description?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A question to ask the user
|
|
28
|
+
*/
|
|
29
|
+
export interface AskUserQuestion {
|
|
30
|
+
/** Unique identifier for this question */
|
|
31
|
+
id: string;
|
|
32
|
+
/** The question text */
|
|
33
|
+
question: string;
|
|
34
|
+
/** Available options to choose from */
|
|
35
|
+
options: AskUserOption[];
|
|
36
|
+
/** Allow multiple selections (default: false) */
|
|
37
|
+
multiSelect?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Input parameters for ask_user tool
|
|
41
|
+
*/
|
|
42
|
+
export interface AskUserInput {
|
|
43
|
+
/** Questions to ask the user (1-4 questions) */
|
|
44
|
+
questions: AskUserQuestion[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result from ask_user tool
|
|
48
|
+
*/
|
|
49
|
+
export interface AskUserResult {
|
|
50
|
+
/** Answers keyed by question ID */
|
|
51
|
+
answers: Record<string, string | string[]>;
|
|
52
|
+
/** Question IDs that were skipped */
|
|
53
|
+
skipped: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Options for creating custom ask_user tool
|
|
57
|
+
*/
|
|
58
|
+
export interface AskUserToolOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Custom handler for asking questions.
|
|
61
|
+
* If not provided, uses readline-based implementation.
|
|
62
|
+
*/
|
|
63
|
+
onAsk?: (questions: AskUserQuestion[]) => Promise<AskUserResult>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Default ask_user tool using readline for basic CLI interaction.
|
|
67
|
+
* Use createAskUserTool() for custom implementations.
|
|
68
|
+
*/
|
|
69
|
+
export declare const askUserTool: Tool<AskUserInput>;
|
|
70
|
+
/**
|
|
71
|
+
* Create a custom ask_user tool with your own UI implementation.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const customAskUser = createAskUserTool({
|
|
76
|
+
* onAsk: async (questions) => {
|
|
77
|
+
* // Show fancy UI overlay
|
|
78
|
+
* const overlay = new AskUserOverlay({ questions });
|
|
79
|
+
* return await ui.showOverlay(overlay);
|
|
80
|
+
* }
|
|
81
|
+
* });
|
|
82
|
+
* agent.registerTool(customAskUser);
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function createAskUserTool(options?: AskUserToolOptions): Tool<AskUserInput>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask User Tool - Gather input from user via questions with options
|
|
3
|
+
*
|
|
4
|
+
* This tool allows the agent to ask the user questions with predefined options.
|
|
5
|
+
* The default implementation uses Node.js readline for basic CLI interaction.
|
|
6
|
+
* Consumers (like CLI apps) can override with custom UI implementations.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Multiple questions in a single call
|
|
10
|
+
* - Options with labels, values, and descriptions
|
|
11
|
+
* - Multi-select support
|
|
12
|
+
* - Factory function for custom implementations
|
|
13
|
+
*/
|
|
14
|
+
/* eslint-disable no-console -- Intentional console output for fallback CLI prompts */
|
|
15
|
+
import * as readline from 'readline';
|
|
16
|
+
import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Default Implementation (readline-based)
|
|
19
|
+
// =============================================================================
|
|
20
|
+
async function askWithReadline(questions) {
|
|
21
|
+
const rl = readline.createInterface({
|
|
22
|
+
input: process.stdin,
|
|
23
|
+
output: process.stdout,
|
|
24
|
+
});
|
|
25
|
+
const askQuestion = (prompt) => {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
rl.question(prompt, (answer) => {
|
|
28
|
+
resolve(answer);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const answers = {};
|
|
33
|
+
const skipped = [];
|
|
34
|
+
try {
|
|
35
|
+
for (const q of questions) {
|
|
36
|
+
// Print question
|
|
37
|
+
console.log(`\n${q.question}`);
|
|
38
|
+
// Print options
|
|
39
|
+
q.options.forEach((opt, i) => {
|
|
40
|
+
const desc = opt.description ? ` - ${opt.description}` : '';
|
|
41
|
+
console.log(` ${String(i + 1)}. ${opt.label}${desc}`);
|
|
42
|
+
});
|
|
43
|
+
if (q.multiSelect) {
|
|
44
|
+
console.log(' (Enter numbers separated by commas, or press Enter to skip)');
|
|
45
|
+
}
|
|
46
|
+
// Get answer
|
|
47
|
+
const prompt = q.multiSelect ? 'Choices: ' : 'Choice: ';
|
|
48
|
+
const answer = await askQuestion(prompt);
|
|
49
|
+
if (!answer.trim()) {
|
|
50
|
+
skipped.push(q.id);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (q.multiSelect) {
|
|
54
|
+
// Parse comma-separated numbers
|
|
55
|
+
const indices = answer
|
|
56
|
+
.split(',')
|
|
57
|
+
.map((s) => parseInt(s.trim(), 10) - 1)
|
|
58
|
+
.filter((i) => i >= 0 && i < q.options.length);
|
|
59
|
+
if (indices.length > 0) {
|
|
60
|
+
answers[q.id] = indices.map((i) => q.options[i].value);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
skipped.push(q.id);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Single selection
|
|
68
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
69
|
+
if (idx >= 0 && idx < q.options.length) {
|
|
70
|
+
answers[q.id] = q.options[idx].value;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Invalid input - try to use as raw value or skip
|
|
74
|
+
skipped.push(q.id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
rl.close();
|
|
81
|
+
}
|
|
82
|
+
return { answers, skipped };
|
|
83
|
+
}
|
|
84
|
+
// =============================================================================
|
|
85
|
+
// Tool Definition
|
|
86
|
+
// =============================================================================
|
|
87
|
+
/**
|
|
88
|
+
* Default ask_user tool using readline for basic CLI interaction.
|
|
89
|
+
* Use createAskUserTool() for custom implementations.
|
|
90
|
+
*/
|
|
91
|
+
export const askUserTool = defineTool({
|
|
92
|
+
name: 'ask_user',
|
|
93
|
+
description: 'Ask the user one or more questions with predefined options. ' +
|
|
94
|
+
'Use this to gather preferences, make decisions, or get user input during workflows. ' +
|
|
95
|
+
'Each question should have 2-4 clear options. ' +
|
|
96
|
+
'Prefer ask_user_simple for single simple questions.',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
questions: {
|
|
101
|
+
type: 'array',
|
|
102
|
+
description: 'Questions to ask (1-4 questions)',
|
|
103
|
+
minItems: 1,
|
|
104
|
+
maxItems: 4,
|
|
105
|
+
items: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
id: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
description: 'Unique identifier for this question',
|
|
111
|
+
},
|
|
112
|
+
question: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'The question text to display',
|
|
115
|
+
},
|
|
116
|
+
options: {
|
|
117
|
+
type: 'array',
|
|
118
|
+
description: 'Available options (2-4 options)',
|
|
119
|
+
minItems: 2,
|
|
120
|
+
maxItems: 4,
|
|
121
|
+
items: {
|
|
122
|
+
type: 'object',
|
|
123
|
+
properties: {
|
|
124
|
+
label: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
description: 'Display text for this option',
|
|
127
|
+
},
|
|
128
|
+
value: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
description: 'Value returned when selected',
|
|
131
|
+
},
|
|
132
|
+
description: {
|
|
133
|
+
type: 'string',
|
|
134
|
+
description: 'Optional explanation of this option',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
required: ['label', 'value'],
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
multiSelect: {
|
|
141
|
+
type: 'boolean',
|
|
142
|
+
description: 'Allow selecting multiple options',
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
required: ['id', 'question', 'options'],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
required: ['questions'],
|
|
150
|
+
},
|
|
151
|
+
execute: async (input) => {
|
|
152
|
+
try {
|
|
153
|
+
const result = await askWithReadline(input.questions);
|
|
154
|
+
return createSuccessResult(result);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
// =============================================================================
|
|
162
|
+
// Factory Function
|
|
163
|
+
// =============================================================================
|
|
164
|
+
/**
|
|
165
|
+
* Create a custom ask_user tool with your own UI implementation.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* const customAskUser = createAskUserTool({
|
|
170
|
+
* onAsk: async (questions) => {
|
|
171
|
+
* // Show fancy UI overlay
|
|
172
|
+
* const overlay = new AskUserOverlay({ questions });
|
|
173
|
+
* return await ui.showOverlay(overlay);
|
|
174
|
+
* }
|
|
175
|
+
* });
|
|
176
|
+
* agent.registerTool(customAskUser);
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export function createAskUserTool(options = {}) {
|
|
180
|
+
const handler = options.onAsk ?? askWithReadline;
|
|
181
|
+
return defineTool({
|
|
182
|
+
name: 'ask_user',
|
|
183
|
+
description: askUserTool.definition.description,
|
|
184
|
+
inputSchema: askUserTool.definition.inputSchema,
|
|
185
|
+
execute: async (input) => {
|
|
186
|
+
try {
|
|
187
|
+
const result = await handler(input.questions);
|
|
188
|
+
return createSuccessResult(result);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
}
|