@sns-myagent/cli 0.3.0 → 0.3.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/bin/.gitkeep +0 -0
- package/bin/snscoder.js +9 -0
- package/dist/cli.js +22026 -0
- package/package.json +2 -1
- package/scripts/fetch-binary.mjs +106 -217
- package/scripts/smoke-test.sh +92 -0
- package/src/agents/ensemble.ts +47 -41
- package/src/agents/strategies/consensus.ts +9 -10
- package/src/agents/strategies/index.ts +12 -0
- package/src/cli/index.ts +5 -1
- package/src/internal-urls/docs-index.generated.txt +0 -2
package/src/agents/ensemble.ts
CHANGED
|
@@ -145,32 +145,35 @@ function createStrategy(name: string, options: Record<string, unknown>): Ensembl
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
function createResilientExecutor(
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
config: ReturnType<typeof getAgentsConfig>["config"],
|
|
149
|
+
options: EnsembleOptions,
|
|
150
150
|
) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
151
|
+
return async (role: string, prompt: string): Promise<AgentResponse> => {
|
|
152
|
+
const agentConfig = config.agents[role];
|
|
153
|
+
const modelKey = agentConfig?.model ?? "default";
|
|
154
|
+
|
|
155
|
+
const breaker = resilience.getCircuitBreaker(modelKey);
|
|
156
|
+
|
|
157
|
+
const result = await resilience.withRetry(
|
|
158
|
+
async () => {
|
|
159
|
+
return resilience.withTimeout(
|
|
160
|
+
async () => {
|
|
161
|
+
// This will be replaced by actual agent execution via the wrapper
|
|
162
|
+
throw new Error("executeAgent must be provided by caller");
|
|
163
|
+
},
|
|
164
|
+
options.taskTimeoutMs ?? config.task_timeout_ms ?? 120_000,
|
|
165
|
+
`ensemble:${role}`,
|
|
166
|
+
);
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
maxAttempts: config.retry_attempts ?? 3,
|
|
170
|
+
baseDelayMs: 1000,
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
if (!result.success) throw result.error ?? new Error("resilient executor failed");
|
|
174
|
+
// Type guard: caller must inject a real AgentResponse executor.
|
|
175
|
+
return result.result as unknown as AgentResponse;
|
|
176
|
+
};
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
function buildCostBreakdown(
|
|
@@ -201,23 +204,26 @@ function buildCostBreakdown(
|
|
|
201
204
|
* Convenience wrapper for non-ensemble usage.
|
|
202
205
|
*/
|
|
203
206
|
export async function executeAgentTask(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
role: string,
|
|
208
|
+
prompt: string,
|
|
209
|
+
executeAgent: (role: string, prompt: string) => Promise<AgentResponse>,
|
|
210
|
+
options: { timeoutMs?: number; retries?: number } = {},
|
|
208
211
|
): Promise<AgentResponse> {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
212
|
+
const config = getAgentsConfig().config;
|
|
213
|
+
const timeoutMs = options.timeoutMs ?? config.task_timeout_ms ?? 120_000;
|
|
214
|
+
const retries = options.retries ?? config.retry_attempts ?? 3;
|
|
215
|
+
|
|
216
|
+
const result = await resilience.withRetry(
|
|
217
|
+
async () =>
|
|
218
|
+
resilience.withTimeout(
|
|
219
|
+
() => executeAgent(role, prompt),
|
|
220
|
+
timeoutMs,
|
|
221
|
+
`agent:${role}`,
|
|
222
|
+
),
|
|
223
|
+
{ maxAttempts: retries },
|
|
224
|
+
);
|
|
225
|
+
if (!result.success) throw result.error ?? new Error("agent task failed");
|
|
226
|
+
return result.result as unknown as AgentResponse;
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
export { getAgentsConfig } from "./config.js";
|
|
@@ -54,16 +54,15 @@ export class ConsensusStrategy implements EnsembleStrategy {
|
|
|
54
54
|
const { winner, agreement } = this.#findConsensus(candidates);
|
|
55
55
|
|
|
56
56
|
return {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
57
|
+
final: winner.content,
|
|
58
|
+
responses: allResponses,
|
|
59
|
+
strategy: this.name,
|
|
60
|
+
rounds: 1,
|
|
61
|
+
totalTimeMs: Date.now() - startTime,
|
|
62
|
+
totalTokens: aggregateTokens(allResponses),
|
|
63
|
+
winner: winner.role,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
67
66
|
|
|
68
67
|
#findConsensus(candidates: AgentResponse[]): { winner: AgentResponse; agreement: number } {
|
|
69
68
|
if (candidates.length === 1) return { winner: candidates[0], agreement: 1 };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensemble strategies — barrel export
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { ConsensusStrategy } from "./consensus.js";
|
|
6
|
+
export type { ConsensusOptions } from "./consensus.js";
|
|
7
|
+
export { CriticStrategy } from "./critic.js";
|
|
8
|
+
export type { CriticOptions } from "./critic.js";
|
|
9
|
+
export { BestOfNStrategy } from "./best-of-n.js";
|
|
10
|
+
export type { BestOfNOptions } from "./best-of-n.js";
|
|
11
|
+
export type { AgentResponse, EnsembleResult, EnsembleStrategy } from "./types.js";
|
|
12
|
+
export { aggregateTokens } from "./types.js";
|
package/src/cli/index.ts
CHANGED
|
@@ -34,7 +34,11 @@ import { fileURLToPath } from "node:url";
|
|
|
34
34
|
function readPackageVersion(): string {
|
|
35
35
|
const fromDefine = process.env.PKG_VERSION;
|
|
36
36
|
if (typeof fromDefine === "string" && fromDefine.length > 0) {
|
|
37
|
-
|
|
37
|
+
// Bun's --define injects the literal value as written. When the value
|
|
38
|
+
// is a JSON string (e.g. --define process.env.PKG_VERSION='"0.3.0"'),
|
|
39
|
+
// the surrounding quotes leak into process.env. Strip them.
|
|
40
|
+
const stripped = fromDefine.replace(/^["']|["']$/g, "");
|
|
41
|
+
if (stripped.length > 0) return stripped;
|
|
38
42
|
}
|
|
39
43
|
try {
|
|
40
44
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
["configuration.md","faq.md","installation.md","memory.md","tbm.md","terminal-ui.md","troubleshooting.md"]
|
|
2
|
-
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
|