@lov3kaizen/agentsea-crews 1.0.0 → 1.1.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/README.md CHANGED
@@ -50,7 +50,7 @@ const config: CrewConfig = {
50
50
  {
51
51
  name: 'researcher',
52
52
  role: researcherRole,
53
- model: 'claude-sonnet-4-20250514',
53
+ model: 'claude-sonnet-4-6',
54
54
  provider: 'anthropic',
55
55
  },
56
56
  ],
@@ -70,6 +70,32 @@ const result = await crew.kickoff();
70
70
  console.log(result.finalOutput);
71
71
  ```
72
72
 
73
+ > **Execution model.** By default, crew agents execute against real LLMs via
74
+ > `@lov3kaizen/agentsea-core` providers (a required peer dependency), so make
75
+ > sure the relevant API key is set (e.g. `ANTHROPIC_API_KEY`). Supported
76
+ > providers out of the box: `anthropic`, `openai`, `gemini`, `ollama`.
77
+ >
78
+ > - To plug in a different integration, pass an `execute` function on the crew
79
+ > config (or to `createCrewAgent`).
80
+ > - For offline scaffolding and tests, set `mock: true` on the crew config to
81
+ > get deterministic mock responses without any network calls.
82
+ >
83
+ > ```typescript
84
+ > // Offline / test mode
85
+ > const crew = createCrew({ ...config, mock: true });
86
+ >
87
+ > // Custom execution backend
88
+ > const crew2 = createCrew({
89
+ > ...config,
90
+ > execute: async (input, systemPrompt) => ({
91
+ > output: await myLlm(systemPrompt, input),
92
+ > tokensUsed: 0,
93
+ > latencyMs: 0,
94
+ > iterations: 1,
95
+ > }),
96
+ > });
97
+ > ```
98
+
73
99
  ### Using Templates
74
100
 
75
101
  ```typescript
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createCrew
3
- } from "./chunk-QMK3HWFX.mjs";
3
+ } from "./chunk-V6VK6BOL.mjs";
4
4
 
5
5
  // src/templates/ResearchCrew.ts
6
6
  var researcherRole = {
@@ -149,7 +149,7 @@ function createResearchCrewConfig(options = {}) {
149
149
  {
150
150
  name: "researcher",
151
151
  role: researcherRole,
152
- model: options.model ?? "claude-sonnet-4-20250514",
152
+ model: options.model ?? "claude-opus-4-8",
153
153
  provider: options.provider ?? "anthropic",
154
154
  tools: ["web-search", "read-document", ...options.tools ?? []],
155
155
  temperature: 0.3
@@ -157,7 +157,7 @@ function createResearchCrewConfig(options = {}) {
157
157
  {
158
158
  name: "analyst",
159
159
  role: analystRole,
160
- model: options.model ?? "claude-sonnet-4-20250514",
160
+ model: options.model ?? "claude-opus-4-8",
161
161
  provider: options.provider ?? "anthropic",
162
162
  tools: ["calculator", "data-analysis", ...options.tools ?? []],
163
163
  temperature: 0.2
@@ -167,7 +167,7 @@ function createResearchCrewConfig(options = {}) {
167
167
  agents.push({
168
168
  name: "writer",
169
169
  role: writerRole,
170
- model: options.model ?? "claude-sonnet-4-20250514",
170
+ model: options.model ?? "claude-opus-4-8",
171
171
  provider: options.provider ?? "anthropic",
172
172
  tools: ["text-editor", ...options.tools ?? []],
173
173
  temperature: 0.5
@@ -380,7 +380,7 @@ Your target audience is: ${options.audience}` : "";
380
380
  ...editorRole,
381
381
  systemPrompt: editorRole.systemPrompt + contentTypePrompt + audiencePrompt
382
382
  },
383
- model: options.model ?? "claude-sonnet-4-20250514",
383
+ model: options.model ?? "claude-opus-4-8",
384
384
  provider: options.provider ?? "anthropic",
385
385
  tools: ["text-editor", ...options.tools ?? []],
386
386
  temperature: 0.3
@@ -391,7 +391,7 @@ Your target audience is: ${options.audience}` : "";
391
391
  ...writerRole2,
392
392
  systemPrompt: writerRole2.systemPrompt + contentTypePrompt + audiencePrompt
393
393
  },
394
- model: options.model ?? "claude-sonnet-4-20250514",
394
+ model: options.model ?? "claude-opus-4-8",
395
395
  provider: options.provider ?? "anthropic",
396
396
  tools: ["web-search", "text-editor", ...options.tools ?? []],
397
397
  temperature: 0.7
@@ -399,7 +399,7 @@ Your target audience is: ${options.audience}` : "";
399
399
  {
400
400
  name: "proofreader",
401
401
  role: proofreaderRole,
402
- model: options.model ?? "claude-sonnet-4-20250514",
402
+ model: options.model ?? "claude-opus-4-8",
403
403
  provider: options.provider ?? "anthropic",
404
404
  tools: ["grammar-checker", "spell-checker", ...options.tools ?? []],
405
405
  temperature: 0.1
@@ -638,7 +638,7 @@ You specialize in: ${options.languages.join(", ")}` : "";
638
638
  ...seniorDeveloperRole,
639
639
  systemPrompt: seniorDeveloperRole.systemPrompt + languagePrompt + strictnessPrompt
640
640
  },
641
- model: options.model ?? "claude-sonnet-4-20250514",
641
+ model: options.model ?? "claude-opus-4-8",
642
642
  provider: options.provider ?? "anthropic",
643
643
  tools: ["code-analyzer", "linter", ...options.tools ?? []],
644
644
  temperature: 0.2
@@ -651,7 +651,7 @@ You specialize in: ${options.languages.join(", ")}` : "";
651
651
  ...securityAnalystRole,
652
652
  systemPrompt: securityAnalystRole.systemPrompt + languagePrompt
653
653
  },
654
- model: options.model ?? "claude-sonnet-4-20250514",
654
+ model: options.model ?? "claude-opus-4-8",
655
655
  provider: options.provider ?? "anthropic",
656
656
  tools: [
657
657
  "security-scanner",
@@ -668,7 +668,7 @@ You specialize in: ${options.languages.join(", ")}` : "";
668
668
  ...performanceEngineerRole,
669
669
  systemPrompt: performanceEngineerRole.systemPrompt + languagePrompt
670
670
  },
671
- model: options.model ?? "claude-sonnet-4-20250514",
671
+ model: options.model ?? "claude-opus-4-8",
672
672
  provider: options.provider ?? "anthropic",
673
673
  tools: ["profiler", "complexity-analyzer", ...options.tools ?? []],
674
674
  temperature: 0.2
@@ -926,7 +926,7 @@ You support ${options.productName}.` : "";
926
926
  ...tier1AgentRole,
927
927
  systemPrompt: tier1AgentRole.systemPrompt + contextAddition
928
928
  },
929
- model: options.model ?? "claude-sonnet-4-20250514",
929
+ model: options.model ?? "claude-opus-4-8",
930
930
  provider: options.provider ?? "anthropic",
931
931
  tools: ["knowledge-base", "ticket-system", ...options.tools ?? []],
932
932
  temperature: 0.4
@@ -939,7 +939,7 @@ You support ${options.productName}.` : "";
939
939
  ...specialistRole,
940
940
  systemPrompt: specialistRole.systemPrompt + contextAddition
941
941
  },
942
- model: options.model ?? "claude-sonnet-4-20250514",
942
+ model: options.model ?? "claude-opus-4-8",
943
943
  provider: options.provider ?? "anthropic",
944
944
  tools: [
945
945
  "diagnostic-tools",
@@ -957,7 +957,7 @@ You support ${options.productName}.` : "";
957
957
  ...escalationManagerRole,
958
958
  systemPrompt: escalationManagerRole.systemPrompt + contextAddition
959
959
  },
960
- model: options.model ?? "claude-sonnet-4-20250514",
960
+ model: options.model ?? "claude-opus-4-8",
961
961
  provider: options.provider ?? "anthropic",
962
962
  tools: [
963
963
  "crm",
@@ -1387,8 +1387,81 @@ var AgentCapabilities = class {
1387
1387
  }
1388
1388
  };
1389
1389
 
1390
+ // src/agents/CoreExecutor.ts
1391
+ async function loadProvider(providerName) {
1392
+ const ctorName = resolveProviderCtorName(providerName);
1393
+ let core;
1394
+ try {
1395
+ core = await import("@lov3kaizen/agentsea-core");
1396
+ } catch {
1397
+ throw new Error(
1398
+ 'CrewAgent requires "@lov3kaizen/agentsea-core" to execute against a real LLM. Install it, or pass a custom `execute` function (or `mock: true`) to createCrewAgent / createCrew.'
1399
+ );
1400
+ }
1401
+ const Ctor = core[ctorName];
1402
+ return new Ctor();
1403
+ }
1404
+ function resolveProviderCtorName(providerName) {
1405
+ switch ((providerName ?? "").toLowerCase()) {
1406
+ case "anthropic":
1407
+ case "claude":
1408
+ return "AnthropicProvider";
1409
+ case "openai":
1410
+ case "gpt":
1411
+ return "OpenAIProvider";
1412
+ case "gemini":
1413
+ case "google":
1414
+ return "GeminiProvider";
1415
+ case "ollama":
1416
+ return "OllamaProvider";
1417
+ default:
1418
+ throw new Error(
1419
+ `CrewAgent: unsupported provider "${providerName}". Supported providers are: anthropic, openai, gemini, ollama. Pass a custom \`execute\` function to createCrewAgent for any other provider.`
1420
+ );
1421
+ }
1422
+ }
1423
+ function createCoreExecutor(config, options = {}) {
1424
+ let providerPromise;
1425
+ const getProvider = () => {
1426
+ if (!providerPromise) {
1427
+ providerPromise = options.provider ? Promise.resolve(options.provider) : loadProvider(config.provider);
1428
+ }
1429
+ return providerPromise;
1430
+ };
1431
+ return async (input, systemPrompt) => {
1432
+ const provider = await getProvider();
1433
+ const start = Date.now();
1434
+ const response = await provider.generateResponse(
1435
+ [{ role: "user", content: input }],
1436
+ {
1437
+ model: config.model,
1438
+ systemPrompt,
1439
+ temperature: config.temperature,
1440
+ maxTokens: config.maxTokens
1441
+ }
1442
+ );
1443
+ return {
1444
+ output: response.content,
1445
+ tokensUsed: response.usage.inputTokens + response.usage.outputTokens,
1446
+ latencyMs: Date.now() - start,
1447
+ iterations: 1
1448
+ };
1449
+ };
1450
+ }
1451
+
1390
1452
  // src/agents/CrewAgent.ts
1391
1453
  import { nanoid as nanoid3 } from "nanoid";
1454
+ function modelCostWeight(model) {
1455
+ const m = (model ?? "").toLowerCase();
1456
+ if (m.includes("opus") || m.includes("gpt-5") || m.includes("o3")) return 5;
1457
+ if (m.includes("sonnet") || m.includes("gpt-4.1") || m.includes("gpt-4") && !m.includes("mini") || m.includes("gemini-1.5-pro") || m.includes("gemini-2.5-pro")) {
1458
+ return 3;
1459
+ }
1460
+ if (m.includes("haiku") || m.includes("mini") || m.includes("flash") || m.includes("llama") || m.includes("mistral")) {
1461
+ return 1;
1462
+ }
1463
+ return 3;
1464
+ }
1392
1465
  var CrewAgent = class _CrewAgent {
1393
1466
  id;
1394
1467
  name;
@@ -1427,10 +1500,11 @@ var CrewAgent = class _CrewAgent {
1427
1500
  */
1428
1501
  async execute(input) {
1429
1502
  if (!this.executeFunc) {
1503
+ const tokensUsed = 100 + Math.min(input.length, 400);
1430
1504
  const mockResult = {
1431
1505
  output: `[Mock response from ${this.name}]: ${input.slice(0, 100)}...`,
1432
- tokensUsed: Math.floor(Math.random() * 500) + 100,
1433
- latencyMs: Math.floor(Math.random() * 2e3) + 500,
1506
+ tokensUsed,
1507
+ latencyMs: 0,
1434
1508
  iterations: 1
1435
1509
  };
1436
1510
  this.totalTokensUsed += mockResult.tokensUsed;
@@ -1533,16 +1607,27 @@ ${JSON.stringify(task.context, null, 2)}`);
1533
1607
  ) ?? true
1534
1608
  ).map((c) => c.name);
1535
1609
  const estimatedTime = this.estimateTaskTime(task);
1610
+ const estimatedCost = this.estimateTaskCost(estimatedTime);
1536
1611
  const reasoning = this.generateBidReasoning(task, confidence, matchedCaps);
1537
1612
  return Promise.resolve({
1538
1613
  agentName: this.name,
1539
1614
  taskId: task.id ?? "unknown",
1540
1615
  confidence,
1541
1616
  estimatedTime,
1617
+ estimatedCost,
1542
1618
  reasoning,
1543
1619
  capabilities: matchedCaps
1544
1620
  });
1545
1621
  }
1622
+ /**
1623
+ * Estimate a relative cost for handling a task. Combines the agent's model
1624
+ * price tier with the estimated effort so the auction `cheapest` criterion
1625
+ * can distinguish a cheap-but-slower model from an expensive-but-faster one.
1626
+ * The unit is arbitrary and only meaningful relative to other bids.
1627
+ */
1628
+ estimateTaskCost(estimatedTime) {
1629
+ return modelCostWeight(this.model) * Math.max(estimatedTime, 1);
1630
+ }
1546
1631
  /**
1547
1632
  * Check if agent has all required capabilities
1548
1633
  */
@@ -1728,7 +1813,13 @@ Please provide helpful guidance based on your expertise.
1728
1813
  }
1729
1814
  };
1730
1815
  function createCrewAgent(options) {
1731
- return new CrewAgent(options);
1816
+ if (options.execute || options.mock) {
1817
+ return new CrewAgent(options);
1818
+ }
1819
+ return new CrewAgent({
1820
+ ...options,
1821
+ execute: createCoreExecutor(options.config, { provider: options.provider })
1822
+ });
1732
1823
  }
1733
1824
 
1734
1825
  // src/agents/AgentRegistry.ts
@@ -2437,9 +2528,9 @@ var AuctionStrategy = class extends BaseDelegationStrategy {
2437
2528
  }, bids[0]);
2438
2529
  case "cheapest":
2439
2530
  return bids.reduce((best, bid) => {
2440
- const bestTime = best.estimatedTime ?? Infinity;
2441
- const bidTime = bid.estimatedTime ?? Infinity;
2442
- return bidTime < bestTime ? bid : best;
2531
+ const bestCost = best.estimatedCost ?? best.estimatedTime ?? Infinity;
2532
+ const bidCost = bid.estimatedCost ?? bid.estimatedTime ?? Infinity;
2533
+ return bidCost < bestCost ? bid : best;
2443
2534
  }, bids[0]);
2444
2535
  case "confidence":
2445
2536
  default:
@@ -2928,9 +3019,8 @@ var ConsensusStrategy = class extends BaseDelegationStrategy {
2928
3019
  */
2929
3020
  async collectVotes(task, voters, candidates) {
2930
3021
  const votes = [];
2931
- const candidateNames = candidates.map((c) => c.name);
2932
3022
  for (const voter of voters) {
2933
- const vote = await this.getVote(voter, task, candidateNames);
3023
+ const vote = await this.getVote(voter, task, candidates);
2934
3024
  if (vote) {
2935
3025
  votes.push(vote);
2936
3026
  }
@@ -2938,33 +3028,35 @@ var ConsensusStrategy = class extends BaseDelegationStrategy {
2938
3028
  return votes;
2939
3029
  }
2940
3030
  /**
2941
- * Get a vote from an agent
3031
+ * Get a vote from an agent.
3032
+ *
3033
+ * Each voter ranks the candidates by how well their capabilities fit the
3034
+ * task (the same `calculateTaskScore` signal the BestMatch/Auction strategies
3035
+ * use), plus a small self-preference bias so an agent leans toward itself when
3036
+ * candidates are otherwise comparable. This is fully deterministic — given the
3037
+ * same agents and task it always produces the same votes — and explainable,
3038
+ * which is what consensus needs. (A future enhancement could replace this with
3039
+ * an actual LLM deliberation per voter; the tally/agreement logic is unchanged.)
2942
3040
  */
2943
3041
  getVote(voter, task, candidates) {
2944
- const scores = [];
2945
- for (const candidateName of candidates) {
2946
- if (candidateName === voter.name) {
2947
- scores.push({ name: candidateName, score: 0.7 });
2948
- } else {
2949
- const randomFactor = 0.8 + Math.random() * 0.4;
2950
- scores.push({
2951
- name: candidateName,
2952
- score: Math.random() * randomFactor
2953
- });
3042
+ if (candidates.length === 0) return Promise.resolve(null);
3043
+ const SELF_PREFERENCE_BONUS = 0.15;
3044
+ const scores = candidates.map((candidate) => {
3045
+ let score = candidate.calculateTaskScore(task);
3046
+ if (candidate.name === voter.name) {
3047
+ score += SELF_PREFERENCE_BONUS;
2954
3048
  }
2955
- }
2956
- scores.sort((a, b) => b.score - a.score);
3049
+ return { name: candidate.name, score };
3050
+ });
3051
+ scores.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name));
2957
3052
  const selected = scores[0];
2958
3053
  if (!selected) return Promise.resolve(null);
2959
- let weight = 1;
2960
- if (this.weightedVoting) {
2961
- weight = voter.calculateTaskScore(task) || 0.5;
2962
- }
3054
+ const weight = this.weightedVoting ? voter.calculateTaskScore(task) || 0.5 : 1;
2963
3055
  return Promise.resolve({
2964
3056
  voter: voter.name,
2965
3057
  candidate: selected.name,
2966
3058
  weight,
2967
- reasoning: `Selected based on perceived suitability (score: ${selected.score.toFixed(2)})`
3059
+ reasoning: `Ranked "${selected.name}" highest by capability fit for the task (score: ${selected.score.toFixed(2)})`
2968
3060
  });
2969
3061
  }
2970
3062
  /**
@@ -3837,13 +3929,24 @@ var ConflictResolver = class {
3837
3929
  resolved: /* @__PURE__ */ new Date()
3838
3930
  };
3839
3931
  }
3932
+ /**
3933
+ * Normalize response content for equality comparison: trim, collapse runs of
3934
+ * whitespace, and lowercase. This groups textually-equivalent answers (ignoring
3935
+ * incidental formatting) over their FULL content rather than a fragile first-N
3936
+ * characters prefix. Note: this is exact-match-after-normalization, not semantic
3937
+ * similarity — agents that express the same idea with different wording will not
3938
+ * group. Semantic grouping would require embeddings (future enhancement).
3939
+ */
3940
+ normalizeContent(content) {
3941
+ return content.trim().replace(/\s+/g, " ").toLowerCase();
3942
+ }
3840
3943
  /**
3841
3944
  * Resolve by voting
3842
3945
  */
3843
3946
  resolveByVoting(conflict, _context) {
3844
3947
  const votes = /* @__PURE__ */ new Map();
3845
3948
  for (const response of conflict.responses) {
3846
- const key = response.content.substring(0, 100);
3949
+ const key = this.normalizeContent(response.content);
3847
3950
  const current = votes.get(key) ?? 0;
3848
3951
  votes.set(key, current + response.confidence);
3849
3952
  }
@@ -3856,7 +3959,7 @@ var ConflictResolver = class {
3856
3959
  }
3857
3960
  }
3858
3961
  const winner = conflict.responses.find(
3859
- (r) => r.content.substring(0, 100) === winningKey
3962
+ (r) => this.normalizeContent(r.content) === winningKey
3860
3963
  );
3861
3964
  return Promise.resolve({
3862
3965
  conflictId: conflict.id,
@@ -3872,7 +3975,31 @@ var ConflictResolver = class {
3872
3975
  * Resolve by authority
3873
3976
  */
3874
3977
  resolveByAuthority(conflict, _context) {
3875
- return Promise.resolve(this.resolveByConfidence(conflict));
3978
+ const ranked = conflict.responses.map((r) => ({
3979
+ response: r,
3980
+ authority: typeof r.metadata?.authority === "number" ? r.metadata.authority : void 0
3981
+ })).filter(
3982
+ (x) => x.authority !== void 0
3983
+ );
3984
+ if (ranked.length === 0) {
3985
+ return Promise.resolve({
3986
+ ...this.resolveByConfidence(conflict),
3987
+ strategy: "authority",
3988
+ explanation: "No authority metadata provided; fell back to highest confidence"
3989
+ });
3990
+ }
3991
+ const winnerEntry = ranked.reduce(
3992
+ (best, cur) => cur.authority > best.authority ? cur : best
3993
+ );
3994
+ return Promise.resolve({
3995
+ conflictId: conflict.id,
3996
+ strategy: "authority",
3997
+ winner: winnerEntry.response,
3998
+ explanation: `Selected response from highest-authority agent "${winnerEntry.response.agentName}" (authority: ${winnerEntry.authority})`,
3999
+ successful: true,
4000
+ escalated: false,
4001
+ resolved: /* @__PURE__ */ new Date()
4002
+ });
3876
4003
  }
3877
4004
  /**
3878
4005
  * Resolve by consensus
@@ -3880,7 +4007,7 @@ var ConflictResolver = class {
3880
4007
  resolveByConsensus(conflict, _context) {
3881
4008
  const contentGroups = /* @__PURE__ */ new Map();
3882
4009
  for (const response of conflict.responses) {
3883
- const key = response.content.substring(0, 100);
4010
+ const key = this.normalizeContent(response.content);
3884
4011
  const group = contentGroups.get(key) ?? [];
3885
4012
  group.push(response);
3886
4013
  contentGroups.set(key, group);
@@ -4044,7 +4171,12 @@ var Crew = class {
4044
4171
  */
4045
4172
  initializeAgents() {
4046
4173
  for (const agentConfig of this.config.agents) {
4047
- const agent = createCrewAgent({ config: agentConfig });
4174
+ const agent = createCrewAgent({
4175
+ config: agentConfig,
4176
+ execute: this.config.execute,
4177
+ mock: this.config.mock,
4178
+ provider: this.config.provider
4179
+ });
4048
4180
  this.addAgent(agent);
4049
4181
  }
4050
4182
  }
@@ -4555,6 +4687,7 @@ export {
4555
4687
  ExecutionContext,
4556
4688
  createExecutionContext,
4557
4689
  AgentCapabilities,
4690
+ createCoreExecutor,
4558
4691
  CrewAgent,
4559
4692
  createCrewAgent,
4560
4693
  AgentRegistry,