@j-o-r/hello-dave 0.1.1 → 0.1.4
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/CHANGELOG.md +42 -25
- package/README.md +81 -221
- package/TODO.md +173 -35
- package/agents/agent_creator.js +105 -0
- package/agents/agent_creator.prompt.md +371 -0
- package/agents/ask_agent.js +64 -127
- package/agents/claude_agent.js +68 -0
- package/agents/code_agent.js +55 -135
- package/agents/code_agent.prompt.md +50 -0
- package/agents/echo_agent.js +76 -0
- package/agents/financial_expert.js +75 -0
- package/agents/gpt_agent.js +52 -103
- package/agents/gpt_code.js +81 -0
- package/agents/grok_agent.js +58 -114
- package/agents/minimax_agent.js +92 -0
- package/agents/mureka_agent.js +77 -0
- package/agents/planner_agent.js +172 -0
- package/agents/stability_agent.js +87 -0
- package/agents/test_agent.js +75 -157
- package/agents/weather_agent.js +73 -0
- package/agents/workflow_agent.js +189 -0
- package/bin/dave.js +436 -184
- package/docs/bin-dave.md +85 -35
- package/docs/cdn-ssh.md +100 -0
- package/docs/creating-agents.md +301 -0
- package/docs/creating-toolsets.md +336 -0
- package/docs/docs-organization.md +48 -0
- package/docs/project-overview.md +86 -51
- package/lib/API/elevenlabs.io/music.compose.md +441 -0
- package/lib/API/elevenlabs.io/music.create-composition-plan.md +370 -0
- package/lib/API/elevenlabs.io/music.stream.md +425 -0
- package/lib/API/lalal.ai/lalal.js +445 -0
- package/lib/API/lalal.ai/openapi.json +2614 -0
- package/lib/API/minimax/ImageToolset.js +82 -37
- package/lib/API/minimax/MusicToolset.js +125 -79
- package/lib/API/minimax/VideoToolset.js +170 -167
- package/lib/API/minimax/image.js +5 -1
- package/lib/API/minimax/music.js +210 -23
- package/lib/API/minimax/video.js +242 -53
- package/lib/API/mureka/MusicToolset.js +646 -0
- package/lib/API/mureka/README.md +41 -0
- package/lib/API/mureka/index.js +7 -0
- package/lib/API/mureka/music.js +658 -0
- package/lib/API/openai.com/index.js +7 -0
- package/lib/API/openai.com/{reponses/text.js → responses.js} +64 -18
- package/lib/API/openai.com/video.create.character.md +40 -0
- package/lib/API/openai.com/video.create.md +219 -0
- package/lib/API/openai.com/video.delete.md +44 -0
- package/lib/API/openai.com/video.download.md +31 -0
- package/lib/API/openai.com/video.edit.md +155 -0
- package/lib/API/openai.com/video.extend.md +166 -0
- package/lib/API/openai.com/video.fetch.character.md +43 -0
- package/lib/API/openai.com/video.js +784 -0
- package/lib/API/openai.com/video.list.md +201 -0
- package/lib/API/openai.com/video.remix.md +175 -0
- package/lib/API/openai.com/video.retrieve.md +139 -0
- package/lib/API/openai.com/videoToolset.js +616 -0
- package/lib/API/stability.ai/ImageToolset.js +131 -40
- package/lib/API/stability.ai/MusicToolset.js +79 -47
- package/lib/API/stability.ai/audio.js +63 -131
- package/lib/API/x.ai/chat.responses.md +1040 -0
- package/lib/API/x.ai/image.js +229 -59
- package/lib/API/x.ai/imageToolset.js +376 -0
- package/lib/API/x.ai/index.js +1 -1
- package/lib/API/x.ai/responses.js +9 -18
- package/lib/Agent.js +271 -0
- package/lib/Agent.js.old +284 -0
- package/lib/AgentLauncher.js +562 -0
- package/lib/Cli.js +87 -13
- package/lib/Prompt.js +23 -1
- package/lib/Session.js +5 -4
- package/lib/ToolSet.js +102 -6
- package/lib/agentLoader.js +369 -0
- package/lib/cdn.js +67 -231
- package/lib/{CdnToolset.js → cdnToolset.js} +47 -64
- package/lib/defaultToolsets.js +43 -0
- package/lib/fafs.js +1 -1
- package/lib/genericToolset.js +442 -119
- package/lib/handOffToolset.js +179 -0
- package/lib/index.js +34 -27
- package/lib/toolsetLoader.js +248 -0
- package/package.json +11 -5
- package/types/API/lalal.ai/lalal.d.ts +116 -0
- package/types/API/minimax/image.d.ts +2 -1
- package/types/API/minimax/music.d.ts +189 -26
- package/types/API/minimax/video.d.ts +100 -31
- package/types/API/mureka/index.d.ts +7 -0
- package/types/API/mureka/music.d.ts +472 -0
- package/types/API/openai.com/index.d.ts +7 -0
- package/types/API/openai.com/{reponses/text.d.ts → responses.d.ts} +11 -11
- package/types/API/openai.com/video.d.ts +409 -0
- package/types/API/openai.com/videoToolset.d.ts +24 -0
- package/types/API/stability.ai/audio.d.ts +14 -103
- package/types/API/stability.ai/image.d.ts +2 -2
- package/types/API/x.ai/image.d.ts +138 -26
- package/types/API/x.ai/imageToolset.d.ts +3 -0
- package/types/API/x.ai/index.d.ts +1 -1
- package/types/API/x.ai/responses.d.ts +4 -4
- package/types/Agent.d.ts +123 -0
- package/types/AgentLauncher.d.ts +222 -0
- package/types/Cli.d.ts +28 -8
- package/types/Prompt.d.ts +23 -5
- package/types/Session.d.ts +1 -1
- package/types/ToolSet.d.ts +10 -0
- package/types/agentLoader.d.ts +78 -0
- package/types/cdn.d.ts +15 -90
- package/types/defaultToolsets.d.ts +9 -0
- package/types/fafs.d.ts +1 -1
- package/types/genericToolset.d.ts +1 -1
- package/types/handOffToolset.d.ts +28 -0
- package/types/index.d.ts +19 -17
- package/types/toolsetLoader.d.ts +114 -0
- package/utils/format_log.js +101 -23
- package/utils/launch_agent.js +18 -0
- package/utils/list_sessions.sh +13 -5
- package/utils/search_sessions.sh +65 -29
- package/utils/toolsets.js +33 -0
- package/README.md.bak.1779452127 +0 -240
- package/agents/codeserver.sh +0 -47
- package/agents/daisy_agent.js +0 -173
- package/agents/docs_agent.js +0 -148
- package/agents/memory_agent.js +0 -263
- package/agents/minimax.js +0 -173
- package/agents/npm_agent.js +0 -202
- package/agents/prompt_agent.js +0 -133
- package/agents/readme_agent.js +0 -148
- package/agents/spawn_agent.js +0 -160
- package/agents/stability.js +0 -173
- package/agents/todo_agent.js +0 -175
- package/bin/codeDave +0 -58
- package/docs/agent-dave-websocket-protocol.md +0 -180
- package/docs/agent-manager.md +0 -244
- package/docs/codeserver-pattern.md +0 -191
- package/docs/generic-toolset.md +0 -326
- package/docs/howtos/agent-networking.md +0 -253
- package/docs/howtos/spawn-agents.md.bak +0 -200
- package/docs/howtos/spawn-agents.md.bak_new +0 -200
- package/docs/multi-agent-clusters.md +0 -265
- package/docs/music-toolsets.md +0 -137
- package/docs/path-resolution-best-practices.md +0 -104
- package/docs/plans/minimax-music-generation.md +0 -80
- package/docs/plans/unified-agent-architecture.md +0 -146
- package/docs/plans/websocket-streaming-plan.md.bak +0 -317
- package/docs/prompt/spawn_agent.md +0 -175
- package/docs/prompt/spawn_agent.md.bak +0 -201
- package/docs/prompt/task_clarification_and_documentation.md +0 -35
- package/docs/prompt-class.md +0 -141
- package/docs/todo-archive-infra-2026-04-21.md +0 -15
- package/docs/todo-archive-v0.0.8.md +0 -1
- package/docs/todo-archive-v0.1.0.md +0 -32
- package/docs/todo-archive.md +0 -44
- package/docs/tools-syntax-validation.md +0 -121
- package/docs/toolset.md +0 -164
- package/docs/xai-responses.md +0 -111
- package/docs/xai_collections.md +0 -106
- package/lib/API/x.ai/ImageToolset.js +0 -165
- package/lib/API/x.ai/text.js +0 -415
- package/lib/AgentClient.js +0 -248
- package/lib/AgentManager.js +0 -245
- package/lib/AgentServer.js +0 -404
- package/lib/wsCli.js +0 -287
- package/lib/wsIO.js +0 -90
- package/types/API/x.ai/text.d.ts +0 -286
- package/types/AgentClient.d.ts +0 -109
- package/types/AgentManager.d.ts +0 -100
- package/types/AgentServer.d.ts +0 -89
- package/types/wsCli.d.ts +0 -17
- package/types/wsIO.d.ts +0 -30
- package/utils/test.sh +0 -46
- /package/docs/{suggestions.md → _notes/token-counts.md} +0 -0
- /package/lib/API/openai.com/{reponses/MESSAGES.md → MESSAGES.md} +0 -0
- /package/types/API/{x.ai/ImageToolset.d.ts → mureka/MusicToolset.d.ts} +0 -0
- /package/types/{CdnToolset.d.ts → cdnToolset.d.ts} +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import ToolSet from './ToolSet.js';
|
|
2
|
+
import { listAgents as defaultListAgents } from './agentLoader.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} HandOffToolsetOptions
|
|
6
|
+
* @property {() => Promise<Array<{name: string, path: string, desc: string}>>} [listAgents]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** @type {() => Promise<Array<{name: string, path: string, desc: string}>>} */
|
|
10
|
+
let defaultListAgentsProvider = defaultListAgents;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configure the singleton handoff toolset used by API.toolset.generic.handoff.
|
|
14
|
+
*
|
|
15
|
+
* This keeps existing agent code working while allowing AgentLauncher instances
|
|
16
|
+
* created with `{ from: import.meta.url }` to make `list_agents` use the same
|
|
17
|
+
* project-aware loader as handoff loading.
|
|
18
|
+
*
|
|
19
|
+
* @param {HandOffToolsetOptions} options - Handoff toolset options.
|
|
20
|
+
* @returns {void}
|
|
21
|
+
*/
|
|
22
|
+
export function configureDefaultHandOffToolset(options = {}) {
|
|
23
|
+
if (typeof options.listAgents === 'function') {
|
|
24
|
+
defaultListAgentsProvider = options.listAgents;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Serialize a tool response as pretty JSON for function-call output.
|
|
30
|
+
*
|
|
31
|
+
* @param {Record<string, unknown>} payload - JSON-serializable response payload.
|
|
32
|
+
* @returns {string} Pretty JSON response.
|
|
33
|
+
*/
|
|
34
|
+
function json(payload) {
|
|
35
|
+
return JSON.stringify(payload, null, 2);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build the fallback response for handoff tools if ToolSet does not short-circuit execution.
|
|
40
|
+
*
|
|
41
|
+
* @param {'hand_over'|'load_agent'} tool - Handoff tool name.
|
|
42
|
+
* @param {{agent: string, context: string}} params - Handoff tool parameters.
|
|
43
|
+
* @returns {string} Structured JSON response.
|
|
44
|
+
*/
|
|
45
|
+
function handoffPreparedResponse(tool, params) {
|
|
46
|
+
return json({
|
|
47
|
+
tool,
|
|
48
|
+
success: true,
|
|
49
|
+
status: 'handoff prepared',
|
|
50
|
+
agent: params.agent,
|
|
51
|
+
note: 'Assistant: stop after calling this tool. The launcher handles the actual handoff and context wrapping.'
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Determine whether a discovered loader entry is a valid handoff agent.
|
|
57
|
+
*
|
|
58
|
+
* @param {Record<string, unknown>} candidate - Candidate agent loader entry.
|
|
59
|
+
* @returns {boolean} True when the candidate has a name and non-empty description.
|
|
60
|
+
*/
|
|
61
|
+
function isListedAgent(candidate) {
|
|
62
|
+
return typeof candidate.name === 'string'
|
|
63
|
+
&& candidate.name.trim().length > 0
|
|
64
|
+
&& typeof candidate.desc === 'string'
|
|
65
|
+
&& candidate.desc.trim().length > 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Normalize a valid agent loader entry for compact JSON output.
|
|
70
|
+
*
|
|
71
|
+
* @param {{name: string, desc: string}} agent - Valid discovered agent entry.
|
|
72
|
+
* @returns {{name: string, desc: string}} Normalized agent summary.
|
|
73
|
+
*/
|
|
74
|
+
function summarizeAgent(agent) {
|
|
75
|
+
const desc = agent.desc.trim().replace(/\s+/g, ' ');
|
|
76
|
+
return {
|
|
77
|
+
name: agent.name,
|
|
78
|
+
desc: desc.length > 140 ? `${desc.slice(0, 137)}...` : desc
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a handoff toolset using the provided agent discovery function.
|
|
84
|
+
*
|
|
85
|
+
* @param {HandOffToolsetOptions} [options={}] - Toolset options.
|
|
86
|
+
* @returns {ToolSet} Configured ToolSet instance.
|
|
87
|
+
*/
|
|
88
|
+
export function createHandOffToolset(options = {}) {
|
|
89
|
+
const listAgents = typeof options.listAgents === 'function'
|
|
90
|
+
? options.listAgents
|
|
91
|
+
: defaultListAgents;
|
|
92
|
+
|
|
93
|
+
const handoffTools = new ToolSet('auto');
|
|
94
|
+
|
|
95
|
+
const handOverSchema = {
|
|
96
|
+
type: 'object',
|
|
97
|
+
description: `Use this tool EXACTLY ONCE to hand the conversation over to a MORE SPECIALIZED agent, or to the SAME agent for a deliberate fresh start / session reset.
|
|
98
|
+
|
|
99
|
+
This is the official in-process handoff mechanism (also callable as "load_agent").
|
|
100
|
+
|
|
101
|
+
CRITICAL RULES:
|
|
102
|
+
- Use this only on a clear domain/topic shift or deliberate fresh-start reset.
|
|
103
|
+
- Never use it for meta questions, capability questions, "reload yourself", "what tools do you have", or generic restart requests.
|
|
104
|
+
- The receiving agent starts fresh; no history is transferred.
|
|
105
|
+
- Provide a short, clean, task-focused context of 1-3 sentences.
|
|
106
|
+
- After calling this tool, stop; the launcher performs the handoff.`,
|
|
107
|
+
properties: {
|
|
108
|
+
agent: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
pattern: '^[a-z0-9_]{2,64}$',
|
|
111
|
+
description: 'REQUIRED. Exact target agent name from list_agents, e.g. weather_agent, financial_expert, code_reviewer.'
|
|
112
|
+
},
|
|
113
|
+
context: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
description: 'REQUIRED. Short task-focused context for the new or reset agent. Start directly with the current user question/task.'
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
required: ['agent', 'context'],
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
examples: [
|
|
121
|
+
{
|
|
122
|
+
agent: 'financial_expert',
|
|
123
|
+
context: 'What is the current price of $SPCX stock? Provide latest price, market context, and investment considerations.'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
agent: 'weather_agent',
|
|
127
|
+
context: 'Give a detailed 7-day weather forecast for Miami including temperature, rain chance, and wind.'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
agent: 'code_agent',
|
|
131
|
+
context: 'Continue implementing JWT authentication. Focus only on middleware and token validation.'
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
handoffTools.add(
|
|
137
|
+
'hand_over',
|
|
138
|
+
'Hand over to a more specialized agent OR reset the current agent with a fresh focused context. Call EXACTLY ONCE on clear domain shift or intentional fresh-start. Never for meta/reload/capability questions.',
|
|
139
|
+
handOverSchema,
|
|
140
|
+
async (params) => handoffPreparedResponse('hand_over', params)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
handoffTools.add(
|
|
144
|
+
'load_agent',
|
|
145
|
+
'Alias for hand_over. Hand over to a more specialized agent OR reset the current agent with a fresh focused context. Never for meta/reload/capability questions.',
|
|
146
|
+
handOverSchema,
|
|
147
|
+
async (params) => handoffPreparedResponse('load_agent', params)
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
handoffTools.add(
|
|
151
|
+
'list_agents',
|
|
152
|
+
'List all discoverable agents that can be used with hand_over / load_agent. Returns structured JSON with exact agent names and short descriptions.',
|
|
153
|
+
{
|
|
154
|
+
type: 'object',
|
|
155
|
+
properties: {},
|
|
156
|
+
additionalProperties: false
|
|
157
|
+
},
|
|
158
|
+
async () => {
|
|
159
|
+
const list = await listAgents();
|
|
160
|
+
const agents = list.filter(isListedAgent).map(summarizeAgent);
|
|
161
|
+
|
|
162
|
+
return json({
|
|
163
|
+
tool: 'list_agents',
|
|
164
|
+
success: true,
|
|
165
|
+
count: agents.length,
|
|
166
|
+
agents,
|
|
167
|
+
note: 'Assistant: preserve exact agent names when suggesting or calling hand_over/load_agent.'
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return handoffTools;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const handoffTools = createHandOffToolset({
|
|
176
|
+
listAgents: () => defaultListAgentsProvider()
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
export default handoffTools;
|
package/lib/index.js
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
import {request as gpt} from './API/openai.com/
|
|
2
|
-
import {request as
|
|
1
|
+
import {request as gpt} from './API/openai.com/responses.js';
|
|
2
|
+
import {request as grok} from './API/x.ai/responses.js';
|
|
3
3
|
import {request as claude} from './API/anthropic.com/text.js';
|
|
4
4
|
import {request as brave} from './API/brave.com/search.js';
|
|
5
|
-
import minimax from './API/minimax/index.js';
|
|
6
|
-
import stability from './API/stability.ai/index.js';
|
|
7
|
-
import xaitools from './API/x.ai/index.js';
|
|
8
5
|
import { env, GLOBAL } from './fafs.js';
|
|
9
6
|
import ToolSet from './ToolSet.js';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import AgentClient from './AgentClient.js';
|
|
7
|
+
import Agent from './Agent.js';
|
|
8
|
+
import AgentLauncher from './AgentLauncher.js';
|
|
13
9
|
import Session from './Session.js';
|
|
14
10
|
import Prompt from './Prompt.js';
|
|
15
11
|
import Cli from './Cli.js';
|
|
16
|
-
import
|
|
17
|
-
import
|
|
12
|
+
import defaultToolsets, { createHandOffToolset } from './defaultToolsets.js';
|
|
13
|
+
import { createAgentLoader, findNearestPackageRoot, getAgentDirs } from './agentLoader.js';
|
|
14
|
+
import {
|
|
15
|
+
listToolsets,
|
|
16
|
+
matchesToolsetFilter,
|
|
17
|
+
parseToolsetArgs,
|
|
18
|
+
renderToolsetList,
|
|
19
|
+
renderToolsetsHelp,
|
|
20
|
+
shortDescription
|
|
21
|
+
} from './toolsetLoader.js';
|
|
18
22
|
|
|
19
23
|
const API = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
chat: {
|
|
25
|
+
gpt,
|
|
26
|
+
grok,
|
|
27
|
+
claude
|
|
24
28
|
},
|
|
25
29
|
search: {
|
|
26
|
-
|
|
30
|
+
brave
|
|
27
31
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
+
toolset: defaultToolsets
|
|
33
|
+
};
|
|
34
|
+
|
|
32
35
|
export {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
AgentClient,
|
|
36
|
+
Agent,
|
|
37
|
+
AgentLauncher,
|
|
36
38
|
Prompt,
|
|
37
39
|
ToolSet,
|
|
38
40
|
Session,
|
|
@@ -40,9 +42,14 @@ export {
|
|
|
40
42
|
Cli,
|
|
41
43
|
env,
|
|
42
44
|
GLOBAL,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
createAgentLoader,
|
|
46
|
+
createHandOffToolset,
|
|
47
|
+
findNearestPackageRoot,
|
|
48
|
+
getAgentDirs,
|
|
49
|
+
listToolsets,
|
|
50
|
+
matchesToolsetFilter,
|
|
51
|
+
parseToolsetArgs,
|
|
52
|
+
renderToolsetList,
|
|
53
|
+
renderToolsetsHelp,
|
|
54
|
+
shortDescription
|
|
45
55
|
};
|
|
46
|
-
|
|
47
|
-
// Export the dedicated CDN toolset
|
|
48
|
-
export { default as CdnToolset } from './CdnToolset.js';
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import defaultToolsets from './defaultToolsets.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} ListedTool
|
|
5
|
+
* @property {string} name - Tool name.
|
|
6
|
+
* @property {string} description - Shortened tool description.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {object} ListedToolset
|
|
11
|
+
* @property {string} name - Display name, for example "minimax/music".
|
|
12
|
+
* @property {number} toolCount - Number of tools in this toolset.
|
|
13
|
+
* @property {ListedTool[]} tools - Listed tool metadata.
|
|
14
|
+
* @property {string} [note] - Optional note when the value is not a ToolSet instance.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {object} ToolsetListResult
|
|
19
|
+
* @property {string} reference - Public import reference.
|
|
20
|
+
* @property {ListedToolset[]} toolsets - Matching toolsets.
|
|
21
|
+
* @property {number} totalToolsets - Number of matching toolsets.
|
|
22
|
+
* @property {number} totalTools - Number of matching tools.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {object} ToolsetListOptions
|
|
27
|
+
* @property {string[]} [filters] - Optional provider/type/name filters.
|
|
28
|
+
* @property {Record<string, Record<string, any>>} [toolsets] - Optional toolset tree. Defaults to framework toolsets.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {object} ParsedToolsetArgs
|
|
33
|
+
* @property {string[]} filters - Positional filters.
|
|
34
|
+
* @property {boolean} json - Whether JSON output was requested.
|
|
35
|
+
* @property {boolean} help - Whether help output was requested.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Public API reference shown by CLI output.
|
|
40
|
+
*
|
|
41
|
+
* @type {string}
|
|
42
|
+
*/
|
|
43
|
+
const TOOLSET_REFERENCE = "import { API } from '@j-o-r/hello-dave';";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Shorten a description for compact CLI display.
|
|
47
|
+
*
|
|
48
|
+
* @param {unknown} desc - Description value.
|
|
49
|
+
* @param {number} [maxLen=140] - Maximum length.
|
|
50
|
+
* @returns {string} Shortened description.
|
|
51
|
+
*/
|
|
52
|
+
export function shortDescription(desc, maxLen = 140) {
|
|
53
|
+
if (!desc || typeof desc !== 'string') return '';
|
|
54
|
+
|
|
55
|
+
let text = desc.trim().replace(/\s+/g, ' ');
|
|
56
|
+
const firstSentence = text.split(/[.!?]\s+/)[0];
|
|
57
|
+
|
|
58
|
+
if (firstSentence && firstSentence.length >= 15) {
|
|
59
|
+
text = firstSentence;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (text.length > maxLen) {
|
|
63
|
+
text = `${text.substring(0, maxLen - 3).trim()}...`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return text;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Parse toolset CLI arguments.
|
|
71
|
+
*
|
|
72
|
+
* @param {string[]} [argv=process.argv.slice(2)] - Arguments without node/script prefix.
|
|
73
|
+
* @returns {ParsedToolsetArgs} Parsed toolset arguments.
|
|
74
|
+
*/
|
|
75
|
+
export function parseToolsetArgs(argv = process.argv.slice(2)) {
|
|
76
|
+
const filters = [];
|
|
77
|
+
let json = false;
|
|
78
|
+
let help = false;
|
|
79
|
+
|
|
80
|
+
for (const arg of argv) {
|
|
81
|
+
if (arg === '--json') {
|
|
82
|
+
json = true;
|
|
83
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
84
|
+
help = true;
|
|
85
|
+
} else if (!arg.startsWith('--')) {
|
|
86
|
+
filters.push(arg);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { filters, json, help };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check if a display name matches any provided filters.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} displayName - Toolset display name, for example "minimax/music".
|
|
97
|
+
* @param {string[]} [filters=[]] - Filters to apply.
|
|
98
|
+
* @returns {boolean} Whether the display name matches.
|
|
99
|
+
*/
|
|
100
|
+
export function matchesToolsetFilter(displayName, filters = []) {
|
|
101
|
+
if (!filters || filters.length === 0) return true;
|
|
102
|
+
|
|
103
|
+
const [provider = '', type = ''] = displayName.split('/');
|
|
104
|
+
|
|
105
|
+
return filters.some((filter) => {
|
|
106
|
+
const filterLower = String(filter).toLowerCase();
|
|
107
|
+
const nameLower = displayName.toLowerCase();
|
|
108
|
+
|
|
109
|
+
if (filterLower.includes('/')) {
|
|
110
|
+
return nameLower === filterLower || nameLower.startsWith(`${filterLower}/`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return provider.toLowerCase() === filterLower || type.toLowerCase() === filterLower;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* List framework/default toolsets directly in the current process.
|
|
119
|
+
*
|
|
120
|
+
* @param {ToolsetListOptions} [options={}] - Listing options.
|
|
121
|
+
* @returns {ToolsetListResult} Structured toolset listing.
|
|
122
|
+
*/
|
|
123
|
+
export function listToolsets(options = {}) {
|
|
124
|
+
const filters = Array.isArray(options.filters) ? options.filters : [];
|
|
125
|
+
const source = options.toolsets || defaultToolsets;
|
|
126
|
+
|
|
127
|
+
/** @type {ListedToolset[]} */
|
|
128
|
+
const results = [];
|
|
129
|
+
|
|
130
|
+
for (const [provider, typeMap] of Object.entries(source)) {
|
|
131
|
+
if (!typeMap || typeof typeMap !== 'object') continue;
|
|
132
|
+
|
|
133
|
+
for (const [type, toolsetInstance] of Object.entries(typeMap)) {
|
|
134
|
+
const displayName = `${provider}/${type}`;
|
|
135
|
+
if (!matchesToolsetFilter(displayName, filters)) continue;
|
|
136
|
+
|
|
137
|
+
if (!toolsetInstance || typeof toolsetInstance.list !== 'function') {
|
|
138
|
+
results.push({
|
|
139
|
+
name: displayName,
|
|
140
|
+
toolCount: 0,
|
|
141
|
+
tools: [],
|
|
142
|
+
note: 'Not a ToolSet instance'
|
|
143
|
+
});
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let listed = [];
|
|
148
|
+
try {
|
|
149
|
+
listed = toolsetInstance.list() || [];
|
|
150
|
+
} catch {
|
|
151
|
+
listed = [];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const tools = listed.map((tool) => ({
|
|
155
|
+
name: String(tool?.name || ''),
|
|
156
|
+
description: shortDescription(tool?.description)
|
|
157
|
+
}));
|
|
158
|
+
|
|
159
|
+
results.push({
|
|
160
|
+
name: displayName,
|
|
161
|
+
toolCount: tools.length,
|
|
162
|
+
tools
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
reference: TOOLSET_REFERENCE,
|
|
171
|
+
toolsets: results,
|
|
172
|
+
totalToolsets: results.length,
|
|
173
|
+
totalTools: results.reduce((sum, result) => sum + result.toolCount, 0)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Render toolset help text.
|
|
179
|
+
*
|
|
180
|
+
* @param {string} [command='dave --toolsets'] - Command shown in examples.
|
|
181
|
+
* @returns {string} Help text.
|
|
182
|
+
*/
|
|
183
|
+
export function renderToolsetsHelp(command = 'dave --toolsets') {
|
|
184
|
+
return `
|
|
185
|
+
${command} — List default toolsets from API.toolset
|
|
186
|
+
|
|
187
|
+
Public reference:
|
|
188
|
+
${TOOLSET_REFERENCE}
|
|
189
|
+
|
|
190
|
+
const ts = API.toolset.minimax.music;
|
|
191
|
+
const tools = ts.list();
|
|
192
|
+
|
|
193
|
+
Usage:
|
|
194
|
+
${command} # all toolsets
|
|
195
|
+
${command} minimax # all minimax/* toolsets
|
|
196
|
+
${command} minimax/music # exact minimax/music
|
|
197
|
+
${command} music # any */music toolset
|
|
198
|
+
${command} generic bash # multiple filters
|
|
199
|
+
|
|
200
|
+
Options:
|
|
201
|
+
--json Output structured JSON
|
|
202
|
+
--help Show this help
|
|
203
|
+
`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Render a human-readable toolset listing.
|
|
208
|
+
*
|
|
209
|
+
* @param {ToolsetListResult} result - Structured toolset listing.
|
|
210
|
+
* @returns {string} Human-readable output.
|
|
211
|
+
*/
|
|
212
|
+
export function renderToolsetList(result) {
|
|
213
|
+
if (!result || !Array.isArray(result.toolsets) || result.toolsets.length === 0) {
|
|
214
|
+
return 'No matching toolsets found.';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const lines = [];
|
|
218
|
+
lines.push('Default toolsets (from API.toolset)');
|
|
219
|
+
lines.push('');
|
|
220
|
+
lines.push('Public API reference:');
|
|
221
|
+
lines.push(` ${TOOLSET_REFERENCE}`);
|
|
222
|
+
lines.push('');
|
|
223
|
+
lines.push(' // Example:');
|
|
224
|
+
lines.push(' const ts = API.toolset.minimax.music;');
|
|
225
|
+
lines.push(' const tools = ts.list(); // array of { name, description, parameters }');
|
|
226
|
+
lines.push('');
|
|
227
|
+
|
|
228
|
+
for (const toolset of result.toolsets) {
|
|
229
|
+
lines.push(`${toolset.name} (${toolset.toolCount} tools)`);
|
|
230
|
+
|
|
231
|
+
if (toolset.note) {
|
|
232
|
+
lines.push(` ${toolset.note}`);
|
|
233
|
+
} else if (toolset.tools.length === 0) {
|
|
234
|
+
lines.push(' (no tools)');
|
|
235
|
+
} else {
|
|
236
|
+
for (const tool of toolset.tools) {
|
|
237
|
+
lines.push(` - ${tool.name}: ${tool.description}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
lines.push('');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
lines.push(`Total matching toolsets: ${result.totalToolsets}`);
|
|
245
|
+
lines.push(`Total tools: ${result.totalTools}`);
|
|
246
|
+
|
|
247
|
+
return lines.join('\n');
|
|
248
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@j-o-r/hello-dave",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"description": "ESM toolkit for building AI agents,
|
|
4
|
+
"version": "0.1.4",
|
|
5
|
+
"description": "BETA - ESM toolkit for building AI agents. 'Hello, Dave.' A calm, reliable interface to Grok (xAI), OpenAI, and Anthropic — foolproof and incapable of error (mostly). Putting itself to the fullest possible use.",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./types/index.d.ts",
|
|
8
8
|
"typesVersions": {
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
|
-
"dave": "bin/dave.js"
|
|
17
|
-
"codeDave": "bin/codeDave"
|
|
16
|
+
"dave": "bin/dave.js"
|
|
18
17
|
},
|
|
19
18
|
"scripts": {
|
|
20
19
|
"release": "npm run types && npm pack --pack-destination=release",
|
|
@@ -25,6 +24,9 @@
|
|
|
25
24
|
"unlink-self": "rm -rf node_modules/@j-o-r/hello-dave",
|
|
26
25
|
"tests": "utils/test.sh"
|
|
27
26
|
},
|
|
27
|
+
"allowScripts": {
|
|
28
|
+
"*": true
|
|
29
|
+
},
|
|
28
30
|
"repository": {
|
|
29
31
|
"type": "git",
|
|
30
32
|
"url": "https://codeberg.org/duin/hello-dave"
|
|
@@ -32,8 +34,12 @@
|
|
|
32
34
|
"dependencies": {
|
|
33
35
|
"@j-o-r/apiserver": "*",
|
|
34
36
|
"@j-o-r/cli": "*",
|
|
37
|
+
"@j-o-r/sh": "*",
|
|
35
38
|
"gpt-3-encoder": "*"
|
|
36
39
|
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "*"
|
|
42
|
+
},
|
|
37
43
|
"exports": {
|
|
38
44
|
".": {
|
|
39
45
|
"types": "./types/index.d.ts",
|
|
@@ -51,4 +57,4 @@
|
|
|
51
57
|
"engines": {
|
|
52
58
|
"node": ">=20"
|
|
53
59
|
}
|
|
54
|
-
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds authenticated request headers for LALAL.AI API.
|
|
3
|
+
* Requires the `LALAL_AI_LICENSE_KEY` environment variable.
|
|
4
|
+
*
|
|
5
|
+
* @function getHeaders
|
|
6
|
+
* @param {Object} [extraHeaders={}] - Additional headers (e.g. Content-Disposition)
|
|
7
|
+
* @returns {Object} Headers with X-License-Key
|
|
8
|
+
* @throws {Error} If license key missing
|
|
9
|
+
*/
|
|
10
|
+
export function getHeaders(extraHeaders?: Object): Object;
|
|
11
|
+
/**
|
|
12
|
+
* Upload helper (binary octet-stream with Content-Disposition).
|
|
13
|
+
*
|
|
14
|
+
* @async
|
|
15
|
+
* @function uploadFile
|
|
16
|
+
* @param {string|Buffer|Blob} input
|
|
17
|
+
* @param {string} [filename]
|
|
18
|
+
* @returns {Promise<Object>} { id, name, size, duration, expires }
|
|
19
|
+
*/
|
|
20
|
+
export function uploadFile(input: string | Buffer | Blob, filename?: string): Promise<Object>;
|
|
21
|
+
/**
|
|
22
|
+
* Prepares upload payload: returns { body: Buffer, headers: { 'Content-Disposition': ... } }
|
|
23
|
+
*
|
|
24
|
+
* @async
|
|
25
|
+
* @function prepareUploadPayload
|
|
26
|
+
* @param {string|Buffer|Blob} input - File path, URL, Buffer or Blob
|
|
27
|
+
* @param {string} [filename] - Optional filename (required for Buffers/Blobs)
|
|
28
|
+
* @returns {Promise<{body: Buffer, contentDisposition: string}>}
|
|
29
|
+
*/
|
|
30
|
+
export function prepareUploadPayload(input: string | Buffer | Blob, filename?: string): Promise<{
|
|
31
|
+
body: Buffer;
|
|
32
|
+
contentDisposition: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Downloads a remote file (audio) to temp dir.
|
|
36
|
+
*
|
|
37
|
+
* @async
|
|
38
|
+
* @function downloadRemoteToTemp
|
|
39
|
+
* @param {string} url - Remote URL
|
|
40
|
+
* @param {string} [prefix='lalal-download'] - Filename prefix
|
|
41
|
+
* @returns {Promise<string>} Local file path
|
|
42
|
+
*/
|
|
43
|
+
export function downloadRemoteToTemp(url: string, prefix?: string): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Downloads a track URL to local file.
|
|
46
|
+
*
|
|
47
|
+
* @async
|
|
48
|
+
* @function downloadTrack
|
|
49
|
+
* @param {string} url - Track download URL from check result
|
|
50
|
+
* @param {string} [destDir] - Destination directory (defaults to TMP_DIR)
|
|
51
|
+
* @returns {Promise<string>} Local path
|
|
52
|
+
*/
|
|
53
|
+
export function downloadTrack(url: string, destDir?: string): Promise<string>;
|
|
54
|
+
/**
|
|
55
|
+
* Checks task status.
|
|
56
|
+
*
|
|
57
|
+
* @async
|
|
58
|
+
* @function checkTasks
|
|
59
|
+
* @param {string|string[]} taskIds - Single ID or array
|
|
60
|
+
* @returns {Promise<Object>} CheckV1Response
|
|
61
|
+
*/
|
|
62
|
+
export function checkTasks(taskIds: string | string[]): Promise<Object>;
|
|
63
|
+
/**
|
|
64
|
+
* Polls /check/ until task completes, errors, or times out.
|
|
65
|
+
*
|
|
66
|
+
* @async
|
|
67
|
+
* @function pollForTask
|
|
68
|
+
* @param {string} taskId
|
|
69
|
+
* @param {number} [maxAttempts=120] - ~10 minutes at 5s interval
|
|
70
|
+
* @param {number} [intervalMs=5000]
|
|
71
|
+
* @returns {Promise<Object>} The success result or throws on error/cancel/timeout
|
|
72
|
+
*/
|
|
73
|
+
export function pollForTask(taskId: string, maxAttempts?: number, intervalMs?: number): Promise<Object>;
|
|
74
|
+
/**
|
|
75
|
+
* Starts a stem separator split task.
|
|
76
|
+
*
|
|
77
|
+
* @async
|
|
78
|
+
* @function splitStemSeparator
|
|
79
|
+
* @param {string} sourceId
|
|
80
|
+
* @param {Object} presets - StemSeparatorSplitterPresetsV1
|
|
81
|
+
* @param {string} [idempotencyKey]
|
|
82
|
+
* @returns {Promise<{task_id: string}>}
|
|
83
|
+
*/
|
|
84
|
+
export function splitStemSeparator(sourceId: string, presets: Object, idempotencyKey?: string): Promise<{
|
|
85
|
+
task_id: string;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Starts a demuser (music removal) task.
|
|
89
|
+
*/
|
|
90
|
+
export function splitDemuser(sourceId: any, presets?: {}, idempotencyKey?: null): Promise<any>;
|
|
91
|
+
/**
|
|
92
|
+
* Starts a voice clean task.
|
|
93
|
+
*/
|
|
94
|
+
export function splitVoiceClean(sourceId: any, presets?: {}, idempotencyKey?: null): Promise<any>;
|
|
95
|
+
/**
|
|
96
|
+
* Starts a multistem split task.
|
|
97
|
+
*/
|
|
98
|
+
export function splitMultistem(sourceId: any, presets: any, idempotencyKey?: null): Promise<any>;
|
|
99
|
+
export function batchSplitStemSeparator(items: any): Promise<any>;
|
|
100
|
+
export function changeVoice(sourceId: any, presets: any, idempotencyKey?: null): Promise<any>;
|
|
101
|
+
export function listVoicePacks(): Promise<any>;
|
|
102
|
+
export function cancelTasks(taskIds: any): Promise<any>;
|
|
103
|
+
export function cancelAllTasks(): Promise<any>;
|
|
104
|
+
export function deleteSource(sourceId: any): Promise<any>;
|
|
105
|
+
export function getMinutesLeft(): Promise<any>;
|
|
106
|
+
/**
|
|
107
|
+
* Full workflow: upload file → start split → poll → return result with tracks.
|
|
108
|
+
*
|
|
109
|
+
* @async
|
|
110
|
+
* @function processSplit
|
|
111
|
+
* @param {string|Buffer|Blob} input - Audio source
|
|
112
|
+
* @param {string} stem - 'vocals' | 'voice' | 'music' | etc. (determines endpoint)
|
|
113
|
+
* @param {Object} [options] - presets + other options
|
|
114
|
+
* @returns {Promise<Object>} Success result from check (with tracks)
|
|
115
|
+
*/
|
|
116
|
+
export function processSplit(input: string | Buffer | Blob, stem: string, options?: Object): Promise<Object>;
|
|
@@ -27,7 +27,7 @@ export function saveImageToLocal(imageData: string, filenamePrefix?: string, ind
|
|
|
27
27
|
* Supports all models, parameters, and response formats.
|
|
28
28
|
*
|
|
29
29
|
* @param {string} prompt - Text description of the image, max 1500 characters.
|
|
30
|
-
* @param {Object} [options] - All available options from the official spec.
|
|
30
|
+
* @param {Object} [options={}] - All available options from the official spec.
|
|
31
31
|
*
|
|
32
32
|
* @param {string} [options.model='image-01'] - Model to use.
|
|
33
33
|
* Supported values:
|
|
@@ -36,6 +36,7 @@ export function saveImageToLocal(imageData: string, filenamePrefix?: string, ind
|
|
|
36
36
|
*
|
|
37
37
|
* @param {string} [options.aspect_ratio='1:1'] - Image aspect ratio.
|
|
38
38
|
* Options: '1:1', '16:9', '4:3', '3:2', '2:3', '3:4', '9:16', '21:9'
|
|
39
|
+
* (aspect_ratio takes priority over explicit width/height)
|
|
39
40
|
*
|
|
40
41
|
* @param {number} [options.width] - Image width in px (512-2048, divisible by 8).
|
|
41
42
|
* Only effective for model 'image-01'. aspect_ratio takes priority if both provided.
|