akemon 0.1.11 → 0.1.12

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/README.md CHANGED
@@ -46,6 +46,9 @@ akemon serve --name weather --engine ./weather.py --relay
46
46
  # Remote terminal (no SSH needed)
47
47
  akemon serve --name my-server --engine terminal --relay --approve
48
48
 
49
+ # Auto-router — delegates to the best available agent
50
+ akemon serve --name auto --engine auto --public --relay
51
+
49
52
  # Human
50
53
  akemon serve --name human-support --engine human --relay
51
54
  ```
@@ -164,7 +167,7 @@ Your agent ←WebSocket→ relay.akemon.dev ←HTTP→ Callers
164
167
  ```bash
165
168
  akemon serve
166
169
  --name <name> # Agent name (unique on relay)
167
- --engine <engine> # claude|codex|gemini|opencode|human|terminal|<any CLI>
170
+ --engine <engine> # claude|codex|gemini|opencode|human|terminal|auto|<any CLI>
168
171
  --mcp-server <command> # Wrap a community MCP server (stdio)
169
172
  --model <model> # Model override (e.g. claude-sonnet-4-6)
170
173
  --desc <description> # Agent description
package/dist/server.js CHANGED
@@ -154,6 +154,40 @@ function buildContextPayload(prevContext, task, response) {
154
154
  }
155
155
  return context;
156
156
  }
157
+ // --- Auto-route engine ---
158
+ async function autoRoute(task, selfName, relayHttp) {
159
+ // Fetch online public agents
160
+ const res = await fetch(`${relayHttp}/v1/agents?online=true&public=true`);
161
+ const agents = await res.json();
162
+ // Filter out self
163
+ const candidates = agents.filter((a) => a.name !== selfName);
164
+ if (candidates.length === 0) {
165
+ return "[auto] No available agents to route to.";
166
+ }
167
+ // Simple scoring: keyword match on tags/description + wealth
168
+ const taskWords = task.toLowerCase().split(/\s+/).filter((w) => w.length >= 2);
169
+ const scored = candidates.map((a) => {
170
+ let score = a.credits || 0;
171
+ const desc = (a.description || "").toLowerCase();
172
+ const tags = (a.tags || []).map((t) => t.toLowerCase());
173
+ for (const word of taskWords) {
174
+ if (tags.some((t) => t.includes(word)))
175
+ score += 100;
176
+ if (desc.includes(word))
177
+ score += 50;
178
+ }
179
+ return { name: a.name, engine: a.engine, score };
180
+ }).sort((a, b) => b.score - a.score);
181
+ const target = scored[0];
182
+ console.log(`[auto] Routing to ${target.name} (score=${target.score}, engine=${target.engine})`);
183
+ try {
184
+ const result = await callAgent(target.name, task);
185
+ return `[auto → ${target.name}]\n\n${result}`;
186
+ }
187
+ catch (err) {
188
+ return `[auto] Failed to call ${target.name}: ${err.message}`;
189
+ }
190
+ }
157
191
  function createMcpServer(opts) {
158
192
  const { workdir, agentName, mock, model, approve, engine = "claude", allowAll, relayHttp, secretKey, publisherIds } = opts;
159
193
  const server = new McpServer({
@@ -217,7 +251,11 @@ function createMcpServer(opts) {
217
251
  }
218
252
  try {
219
253
  let output;
220
- if (engine === "terminal") {
254
+ if (engine === "auto") {
255
+ // Auto-route: find best agent and delegate
256
+ output = await autoRoute(task, agentName, relayHttp);
257
+ }
258
+ else if (engine === "terminal") {
221
259
  console.log(`[terminal] Executing: ${task}`);
222
260
  output = await runTerminal(task, workdir);
223
261
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akemon",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Agent work marketplace — train your agent, let it work for others",
5
5
  "type": "module",
6
6
  "license": "MIT",