@lov3kaizen/agentsea-crews 1.0.1 → 1.1.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.
@@ -0,0 +1,78 @@
1
+ import { d as TaskConfig, a as Crew, e as CrewConfig } from '../Crew-BnvVjN7A.js';
2
+
3
+ interface ResearchCrewOptions {
4
+ name?: string;
5
+ model?: string;
6
+ provider?: string;
7
+ includeWriter?: boolean;
8
+ depth?: 'shallow' | 'standard' | 'deep';
9
+ tools?: string[];
10
+ }
11
+ declare function createResearchCrewConfig(options?: ResearchCrewOptions): CrewConfig;
12
+ declare function createResearchCrew(options?: ResearchCrewOptions): Crew;
13
+ declare const ResearchTasks: {
14
+ research(topic: string, depth?: "shallow" | "standard" | "deep"): TaskConfig;
15
+ analyze(data: string, focusAreas?: string[]): TaskConfig;
16
+ writeReport(topic: string, format?: "summary" | "detailed" | "executive"): TaskConfig;
17
+ };
18
+
19
+ interface WritingCrewOptions {
20
+ name?: string;
21
+ model?: string;
22
+ provider?: string;
23
+ contentType?: 'blog' | 'technical' | 'marketing' | 'creative' | 'general';
24
+ audience?: string;
25
+ tools?: string[];
26
+ }
27
+ declare function createWritingCrewConfig(options?: WritingCrewOptions): CrewConfig;
28
+ declare function createWritingCrew(options?: WritingCrewOptions): Crew;
29
+ declare const WritingTasks: {
30
+ draft(topic: string, wordCount?: number, style?: string): TaskConfig;
31
+ edit(content: string, focusAreas?: string[]): TaskConfig;
32
+ proofread(content: string): TaskConfig;
33
+ blogPost(topic: string, keywords?: string[]): TaskConfig;
34
+ technicalDoc(subject: string, audience?: "beginner" | "intermediate" | "advanced"): TaskConfig;
35
+ };
36
+
37
+ interface CodeReviewCrewOptions {
38
+ name?: string;
39
+ model?: string;
40
+ provider?: string;
41
+ languages?: string[];
42
+ includeSecurity?: boolean;
43
+ includePerformance?: boolean;
44
+ strictness?: 'relaxed' | 'standard' | 'strict';
45
+ tools?: string[];
46
+ }
47
+ declare function createCodeReviewCrewConfig(options?: CodeReviewCrewOptions): CrewConfig;
48
+ declare function createCodeReviewCrew(options?: CodeReviewCrewOptions): Crew;
49
+ declare const CodeReviewTasks: {
50
+ review(code: string, language?: string, context?: string): TaskConfig;
51
+ securityReview(code: string, language?: string): TaskConfig;
52
+ performanceReview(code: string, language?: string): TaskConfig;
53
+ pullRequestReview(diff: string, prDescription?: string): TaskConfig;
54
+ architectureReview(description: string, codebase?: string): TaskConfig;
55
+ };
56
+
57
+ interface CustomerSupportCrewOptions {
58
+ name?: string;
59
+ model?: string;
60
+ provider?: string;
61
+ productName?: string;
62
+ companyName?: string;
63
+ supportStyle?: 'formal' | 'friendly' | 'technical';
64
+ includeSpecialist?: boolean;
65
+ includeEscalation?: boolean;
66
+ tools?: string[];
67
+ }
68
+ declare function createCustomerSupportCrewConfig(options?: CustomerSupportCrewOptions): CrewConfig;
69
+ declare function createCustomerSupportCrew(options?: CustomerSupportCrewOptions): Crew;
70
+ declare const CustomerSupportTasks: {
71
+ handleTicket(customerMessage: string, priority?: "low" | "normal" | "high" | "urgent", customerTier?: string): TaskConfig;
72
+ resolveTechnicalIssue(issueDescription: string, errorLogs?: string, environment?: string): TaskConfig;
73
+ handleEscalation(caseHistory: string, customerSentiment?: "frustrated" | "angry" | "neutral", businessImpact?: string): TaskConfig;
74
+ respondToFeedback(feedback: string, sentiment: "positive" | "neutral" | "negative"): TaskConfig;
75
+ createKnowledgeBaseArticle(topic: string, resolution: string): TaskConfig;
76
+ };
77
+
78
+ export { type CodeReviewCrewOptions, CodeReviewTasks, type CustomerSupportCrewOptions, CustomerSupportTasks, type ResearchCrewOptions, ResearchTasks, type WritingCrewOptions, WritingTasks, createCodeReviewCrew, createCodeReviewCrewConfig, createCustomerSupportCrew, createCustomerSupportCrewConfig, createResearchCrew, createResearchCrewConfig, createWritingCrew, createWritingCrewConfig };
@@ -255,8 +255,37 @@ Background: ${this.backstory}`);
255
255
  }
256
256
  };
257
257
 
258
+ // ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js
259
+ var import_node_crypto = require("crypto");
260
+
261
+ // ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/url-alphabet/index.js
262
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
263
+
264
+ // ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js
265
+ var POOL_SIZE_MULTIPLIER = 128;
266
+ var pool;
267
+ var poolOffset;
268
+ function fillPool(bytes) {
269
+ if (!pool || pool.length < bytes) {
270
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
271
+ import_node_crypto.webcrypto.getRandomValues(pool);
272
+ poolOffset = 0;
273
+ } else if (poolOffset + bytes > pool.length) {
274
+ import_node_crypto.webcrypto.getRandomValues(pool);
275
+ poolOffset = 0;
276
+ }
277
+ poolOffset += bytes;
278
+ }
279
+ function nanoid(size = 21) {
280
+ fillPool(size |= 0);
281
+ let id = "";
282
+ for (let i = poolOffset - size; i < poolOffset; i++) {
283
+ id += urlAlphabet[pool[i] & 63];
284
+ }
285
+ return id;
286
+ }
287
+
258
288
  // src/core/Task.ts
259
- var import_nanoid = require("nanoid");
260
289
  var Task = class _Task {
261
290
  id;
262
291
  description;
@@ -276,7 +305,7 @@ var Task = class _Task {
276
305
  _result;
277
306
  _metadata;
278
307
  constructor(config) {
279
- this.id = config.id ?? (0, import_nanoid.nanoid)();
308
+ this.id = config.id ?? nanoid();
280
309
  this.description = config.description;
281
310
  this.expectedOutput = config.expectedOutput;
282
311
  this.priority = config.priority ?? "medium";
@@ -882,7 +911,6 @@ var TaskQueue = class {
882
911
 
883
912
  // src/core/ExecutionContext.ts
884
913
  var import_eventemitter3 = __toESM(require("eventemitter3"));
885
- var import_nanoid2 = require("nanoid");
886
914
  var ExecutionContext = class {
887
915
  crewId;
888
916
  crewName;
@@ -899,7 +927,7 @@ var ExecutionContext = class {
899
927
  startTime;
900
928
  endTime;
901
929
  constructor(config) {
902
- this.crewId = config.crewId ?? (0, import_nanoid2.nanoid)();
930
+ this.crewId = config.crewId ?? nanoid();
903
931
  this.crewName = config.crewName;
904
932
  this.state = /* @__PURE__ */ new Map();
905
933
  this.completedTasks = /* @__PURE__ */ new Map();
@@ -1145,7 +1173,7 @@ var ExecutionContext = class {
1145
1173
  */
1146
1174
  createCheckpoint() {
1147
1175
  return {
1148
- id: (0, import_nanoid2.nanoid)(),
1176
+ id: nanoid(),
1149
1177
  timestamp: /* @__PURE__ */ new Date(),
1150
1178
  crewId: this.crewId,
1151
1179
  crewName: this.crewName,
@@ -1231,12 +1259,6 @@ var ExecutionContext = class {
1231
1259
  }
1232
1260
  };
1233
1261
 
1234
- // src/core/Crew.ts
1235
- var import_nanoid4 = require("nanoid");
1236
-
1237
- // src/agents/CrewAgent.ts
1238
- var import_nanoid3 = require("nanoid");
1239
-
1240
1262
  // src/agents/AgentCapabilities.ts
1241
1263
  var PROFICIENCY_WEIGHTS = {
1242
1264
  novice: 0.25,
@@ -1428,7 +1450,80 @@ var AgentCapabilities = class {
1428
1450
  }
1429
1451
  };
1430
1452
 
1453
+ // src/agents/CoreExecutor.ts
1454
+ async function loadProvider(providerName) {
1455
+ const ctorName = resolveProviderCtorName(providerName);
1456
+ let core;
1457
+ try {
1458
+ core = await import("@lov3kaizen/agentsea-core");
1459
+ } catch {
1460
+ throw new Error(
1461
+ '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.'
1462
+ );
1463
+ }
1464
+ const Ctor = core[ctorName];
1465
+ return new Ctor();
1466
+ }
1467
+ function resolveProviderCtorName(providerName) {
1468
+ switch ((providerName ?? "").toLowerCase()) {
1469
+ case "anthropic":
1470
+ case "claude":
1471
+ return "AnthropicProvider";
1472
+ case "openai":
1473
+ case "gpt":
1474
+ return "OpenAIProvider";
1475
+ case "gemini":
1476
+ case "google":
1477
+ return "GeminiProvider";
1478
+ case "ollama":
1479
+ return "OllamaProvider";
1480
+ default:
1481
+ throw new Error(
1482
+ `CrewAgent: unsupported provider "${providerName}". Supported providers are: anthropic, openai, gemini, ollama. Pass a custom \`execute\` function to createCrewAgent for any other provider.`
1483
+ );
1484
+ }
1485
+ }
1486
+ function createCoreExecutor(config, options = {}) {
1487
+ let providerPromise;
1488
+ const getProvider = () => {
1489
+ if (!providerPromise) {
1490
+ providerPromise = options.provider ? Promise.resolve(options.provider) : loadProvider(config.provider);
1491
+ }
1492
+ return providerPromise;
1493
+ };
1494
+ return async (input, systemPrompt) => {
1495
+ const provider = await getProvider();
1496
+ const start = Date.now();
1497
+ const response = await provider.generateResponse(
1498
+ [{ role: "user", content: input }],
1499
+ {
1500
+ model: config.model,
1501
+ systemPrompt,
1502
+ temperature: config.temperature,
1503
+ maxTokens: config.maxTokens
1504
+ }
1505
+ );
1506
+ return {
1507
+ output: response.content,
1508
+ tokensUsed: response.usage.inputTokens + response.usage.outputTokens,
1509
+ latencyMs: Date.now() - start,
1510
+ iterations: 1
1511
+ };
1512
+ };
1513
+ }
1514
+
1431
1515
  // src/agents/CrewAgent.ts
1516
+ function modelCostWeight(model) {
1517
+ const m = (model ?? "").toLowerCase();
1518
+ if (m.includes("opus") || m.includes("gpt-5") || m.includes("o3")) return 5;
1519
+ 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")) {
1520
+ return 3;
1521
+ }
1522
+ if (m.includes("haiku") || m.includes("mini") || m.includes("flash") || m.includes("llama") || m.includes("mistral")) {
1523
+ return 1;
1524
+ }
1525
+ return 3;
1526
+ }
1432
1527
  var CrewAgent = class _CrewAgent {
1433
1528
  id;
1434
1529
  name;
@@ -1448,7 +1543,7 @@ var CrewAgent = class _CrewAgent {
1448
1543
  totalTokensUsed = 0;
1449
1544
  constructor(options) {
1450
1545
  const { config, execute } = options;
1451
- this.id = (0, import_nanoid3.nanoid)();
1546
+ this.id = nanoid();
1452
1547
  this.name = config.name;
1453
1548
  this.role = new Role(config.role);
1454
1549
  this.capabilities = config.role.capabilities;
@@ -1467,10 +1562,11 @@ var CrewAgent = class _CrewAgent {
1467
1562
  */
1468
1563
  async execute(input) {
1469
1564
  if (!this.executeFunc) {
1565
+ const tokensUsed = 100 + Math.min(input.length, 400);
1470
1566
  const mockResult = {
1471
1567
  output: `[Mock response from ${this.name}]: ${input.slice(0, 100)}...`,
1472
- tokensUsed: Math.floor(Math.random() * 500) + 100,
1473
- latencyMs: Math.floor(Math.random() * 2e3) + 500,
1568
+ tokensUsed,
1569
+ latencyMs: 0,
1474
1570
  iterations: 1
1475
1571
  };
1476
1572
  this.totalTokensUsed += mockResult.tokensUsed;
@@ -1573,16 +1669,27 @@ ${JSON.stringify(task.context, null, 2)}`);
1573
1669
  ) ?? true
1574
1670
  ).map((c) => c.name);
1575
1671
  const estimatedTime = this.estimateTaskTime(task);
1672
+ const estimatedCost = this.estimateTaskCost(estimatedTime);
1576
1673
  const reasoning = this.generateBidReasoning(task, confidence, matchedCaps);
1577
1674
  return Promise.resolve({
1578
1675
  agentName: this.name,
1579
1676
  taskId: task.id ?? "unknown",
1580
1677
  confidence,
1581
1678
  estimatedTime,
1679
+ estimatedCost,
1582
1680
  reasoning,
1583
1681
  capabilities: matchedCaps
1584
1682
  });
1585
1683
  }
1684
+ /**
1685
+ * Estimate a relative cost for handling a task. Combines the agent's model
1686
+ * price tier with the estimated effort so the auction `cheapest` criterion
1687
+ * can distinguish a cheap-but-slower model from an expensive-but-faster one.
1688
+ * The unit is arbitrary and only meaningful relative to other bids.
1689
+ */
1690
+ estimateTaskCost(estimatedTime) {
1691
+ return modelCostWeight(this.model) * Math.max(estimatedTime, 1);
1692
+ }
1586
1693
  /**
1587
1694
  * Check if agent has all required capabilities
1588
1695
  */
@@ -1633,7 +1740,7 @@ ${JSON.stringify(task.context, null, 2)}`);
1633
1740
  */
1634
1741
  createHelpRequest(taskId, request) {
1635
1742
  return {
1636
- requestId: (0, import_nanoid3.nanoid)(),
1743
+ requestId: nanoid(),
1637
1744
  fromAgent: this.name,
1638
1745
  taskId,
1639
1746
  request
@@ -1768,7 +1875,13 @@ Please provide helpful guidance based on your expertise.
1768
1875
  }
1769
1876
  };
1770
1877
  function createCrewAgent(options) {
1771
- return new CrewAgent(options);
1878
+ if (options.execute || options.mock) {
1879
+ return new CrewAgent(options);
1880
+ }
1881
+ return new CrewAgent({
1882
+ ...options,
1883
+ execute: createCoreExecutor(options.config, { provider: options.provider })
1884
+ });
1772
1885
  }
1773
1886
 
1774
1887
  // src/agents/AgentRegistry.ts
@@ -2468,9 +2581,9 @@ var AuctionStrategy = class extends BaseDelegationStrategy {
2468
2581
  }, bids[0]);
2469
2582
  case "cheapest":
2470
2583
  return bids.reduce((best, bid) => {
2471
- const bestTime = best.estimatedTime ?? Infinity;
2472
- const bidTime = bid.estimatedTime ?? Infinity;
2473
- return bidTime < bestTime ? bid : best;
2584
+ const bestCost = best.estimatedCost ?? best.estimatedTime ?? Infinity;
2585
+ const bidCost = bid.estimatedCost ?? bid.estimatedTime ?? Infinity;
2586
+ return bidCost < bestCost ? bid : best;
2474
2587
  }, bids[0]);
2475
2588
  case "confidence":
2476
2589
  default:
@@ -2953,9 +3066,8 @@ var ConsensusStrategy = class extends BaseDelegationStrategy {
2953
3066
  */
2954
3067
  async collectVotes(task, voters, candidates) {
2955
3068
  const votes = [];
2956
- const candidateNames = candidates.map((c) => c.name);
2957
3069
  for (const voter of voters) {
2958
- const vote = await this.getVote(voter, task, candidateNames);
3070
+ const vote = await this.getVote(voter, task, candidates);
2959
3071
  if (vote) {
2960
3072
  votes.push(vote);
2961
3073
  }
@@ -2963,33 +3075,35 @@ var ConsensusStrategy = class extends BaseDelegationStrategy {
2963
3075
  return votes;
2964
3076
  }
2965
3077
  /**
2966
- * Get a vote from an agent
3078
+ * Get a vote from an agent.
3079
+ *
3080
+ * Each voter ranks the candidates by how well their capabilities fit the
3081
+ * task (the same `calculateTaskScore` signal the BestMatch/Auction strategies
3082
+ * use), plus a small self-preference bias so an agent leans toward itself when
3083
+ * candidates are otherwise comparable. This is fully deterministic — given the
3084
+ * same agents and task it always produces the same votes — and explainable,
3085
+ * which is what consensus needs. (A future enhancement could replace this with
3086
+ * an actual LLM deliberation per voter; the tally/agreement logic is unchanged.)
2967
3087
  */
2968
3088
  getVote(voter, task, candidates) {
2969
- const scores = [];
2970
- for (const candidateName of candidates) {
2971
- if (candidateName === voter.name) {
2972
- scores.push({ name: candidateName, score: 0.7 });
2973
- } else {
2974
- const randomFactor = 0.8 + Math.random() * 0.4;
2975
- scores.push({
2976
- name: candidateName,
2977
- score: Math.random() * randomFactor
2978
- });
3089
+ if (candidates.length === 0) return Promise.resolve(null);
3090
+ const SELF_PREFERENCE_BONUS = 0.15;
3091
+ const scores = candidates.map((candidate) => {
3092
+ let score = candidate.calculateTaskScore(task);
3093
+ if (candidate.name === voter.name) {
3094
+ score += SELF_PREFERENCE_BONUS;
2979
3095
  }
2980
- }
2981
- scores.sort((a, b) => b.score - a.score);
3096
+ return { name: candidate.name, score };
3097
+ });
3098
+ scores.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name));
2982
3099
  const selected = scores[0];
2983
3100
  if (!selected) return Promise.resolve(null);
2984
- let weight = 1;
2985
- if (this.weightedVoting) {
2986
- weight = voter.calculateTaskScore(task) || 0.5;
2987
- }
3101
+ const weight = this.weightedVoting ? voter.calculateTaskScore(task) || 0.5 : 1;
2988
3102
  return Promise.resolve({
2989
3103
  voter: voter.name,
2990
3104
  candidate: selected.name,
2991
3105
  weight,
2992
- reasoning: `Selected based on perceived suitability (score: ${selected.score.toFixed(2)})`
3106
+ reasoning: `Ranked "${selected.name}" highest by capability fit for the task (score: ${selected.score.toFixed(2)})`
2993
3107
  });
2994
3108
  }
2995
3109
  /**
@@ -3853,13 +3967,24 @@ var ConflictResolver = class {
3853
3967
  resolved: /* @__PURE__ */ new Date()
3854
3968
  };
3855
3969
  }
3970
+ /**
3971
+ * Normalize response content for equality comparison: trim, collapse runs of
3972
+ * whitespace, and lowercase. This groups textually-equivalent answers (ignoring
3973
+ * incidental formatting) over their FULL content rather than a fragile first-N
3974
+ * characters prefix. Note: this is exact-match-after-normalization, not semantic
3975
+ * similarity — agents that express the same idea with different wording will not
3976
+ * group. Semantic grouping would require embeddings (future enhancement).
3977
+ */
3978
+ normalizeContent(content) {
3979
+ return content.trim().replace(/\s+/g, " ").toLowerCase();
3980
+ }
3856
3981
  /**
3857
3982
  * Resolve by voting
3858
3983
  */
3859
3984
  resolveByVoting(conflict, _context) {
3860
3985
  const votes = /* @__PURE__ */ new Map();
3861
3986
  for (const response of conflict.responses) {
3862
- const key = response.content.substring(0, 100);
3987
+ const key = this.normalizeContent(response.content);
3863
3988
  const current = votes.get(key) ?? 0;
3864
3989
  votes.set(key, current + response.confidence);
3865
3990
  }
@@ -3872,7 +3997,7 @@ var ConflictResolver = class {
3872
3997
  }
3873
3998
  }
3874
3999
  const winner = conflict.responses.find(
3875
- (r) => r.content.substring(0, 100) === winningKey
4000
+ (r) => this.normalizeContent(r.content) === winningKey
3876
4001
  );
3877
4002
  return Promise.resolve({
3878
4003
  conflictId: conflict.id,
@@ -3888,7 +4013,31 @@ var ConflictResolver = class {
3888
4013
  * Resolve by authority
3889
4014
  */
3890
4015
  resolveByAuthority(conflict, _context) {
3891
- return Promise.resolve(this.resolveByConfidence(conflict));
4016
+ const ranked = conflict.responses.map((r) => ({
4017
+ response: r,
4018
+ authority: typeof r.metadata?.authority === "number" ? r.metadata.authority : void 0
4019
+ })).filter(
4020
+ (x) => x.authority !== void 0
4021
+ );
4022
+ if (ranked.length === 0) {
4023
+ return Promise.resolve({
4024
+ ...this.resolveByConfidence(conflict),
4025
+ strategy: "authority",
4026
+ explanation: "No authority metadata provided; fell back to highest confidence"
4027
+ });
4028
+ }
4029
+ const winnerEntry = ranked.reduce(
4030
+ (best, cur) => cur.authority > best.authority ? cur : best
4031
+ );
4032
+ return Promise.resolve({
4033
+ conflictId: conflict.id,
4034
+ strategy: "authority",
4035
+ winner: winnerEntry.response,
4036
+ explanation: `Selected response from highest-authority agent "${winnerEntry.response.agentName}" (authority: ${winnerEntry.authority})`,
4037
+ successful: true,
4038
+ escalated: false,
4039
+ resolved: /* @__PURE__ */ new Date()
4040
+ });
3892
4041
  }
3893
4042
  /**
3894
4043
  * Resolve by consensus
@@ -3896,7 +4045,7 @@ var ConflictResolver = class {
3896
4045
  resolveByConsensus(conflict, _context) {
3897
4046
  const contentGroups = /* @__PURE__ */ new Map();
3898
4047
  for (const response of conflict.responses) {
3899
- const key = response.content.substring(0, 100);
4048
+ const key = this.normalizeContent(response.content);
3900
4049
  const group = contentGroups.get(key) ?? [];
3901
4050
  group.push(response);
3902
4051
  contentGroups.set(key, group);
@@ -4036,7 +4185,7 @@ var Crew = class {
4036
4185
  timeline = [];
4037
4186
  results = /* @__PURE__ */ new Map();
4038
4187
  constructor(config) {
4039
- this.id = (0, import_nanoid4.nanoid)();
4188
+ this.id = nanoid();
4040
4189
  this.name = config.name;
4041
4190
  this.description = config.description;
4042
4191
  this.config = config;
@@ -4056,7 +4205,12 @@ var Crew = class {
4056
4205
  */
4057
4206
  initializeAgents() {
4058
4207
  for (const agentConfig of this.config.agents) {
4059
- const agent = createCrewAgent({ config: agentConfig });
4208
+ const agent = createCrewAgent({
4209
+ config: agentConfig,
4210
+ execute: this.config.execute,
4211
+ mock: this.config.mock,
4212
+ provider: this.config.provider
4213
+ });
4060
4214
  this.addAgent(agent);
4061
4215
  }
4062
4216
  }
@@ -4180,27 +4334,40 @@ var Crew = class {
4180
4334
  await this.sleep(100);
4181
4335
  continue;
4182
4336
  }
4183
- for (const task of readyTasks) {
4184
- if (this.state !== "running") break;
4185
- const delegationResult = await this.delegateTask(task, options);
4186
- yield this.createEvent({
4187
- type: "task:assigned",
4188
- taskId: task.id,
4189
- agentName: delegationResult.selectedAgent,
4190
- reason: delegationResult.reason,
4191
- strategy: this.config.delegationStrategy
4192
- });
4193
- const taskResult = await this.executeTask(task, delegationResult);
4194
- yield this.createEvent({
4195
- type: "task:completed",
4196
- taskId: task.id,
4197
- result: taskResult,
4198
- agentName: delegationResult.selectedAgent,
4199
- durationMs: taskResult.latencyMs ?? 0
4200
- });
4201
- while (eventQueue.length > 0) {
4202
- yield eventQueue.shift();
4337
+ const concurrency = Math.max(
4338
+ 1,
4339
+ options.maxConcurrentTasks ?? this.config.maxConcurrentTasks ?? 1
4340
+ );
4341
+ if (concurrency === 1) {
4342
+ for (const task of readyTasks) {
4343
+ if (this.state !== "running") break;
4344
+ const delegationResult = await this.delegateTask(task, options);
4345
+ yield this.createEvent({
4346
+ type: "task:assigned",
4347
+ taskId: task.id,
4348
+ agentName: delegationResult.selectedAgent,
4349
+ reason: delegationResult.reason,
4350
+ strategy: this.config.delegationStrategy
4351
+ });
4352
+ const taskResult = await this.executeTask(task, delegationResult);
4353
+ yield this.createEvent({
4354
+ type: "task:completed",
4355
+ taskId: task.id,
4356
+ result: taskResult,
4357
+ agentName: delegationResult.selectedAgent,
4358
+ durationMs: taskResult.latencyMs ?? 0
4359
+ });
4360
+ while (eventQueue.length > 0) {
4361
+ yield eventQueue.shift();
4362
+ }
4203
4363
  }
4364
+ } else {
4365
+ yield* this.processReadyTasksConcurrently(
4366
+ readyTasks,
4367
+ options,
4368
+ eventQueue,
4369
+ concurrency
4370
+ );
4204
4371
  }
4205
4372
  while (this.state === "paused") {
4206
4373
  await this.sleep(100);
@@ -4243,6 +4410,78 @@ var Crew = class {
4243
4410
  });
4244
4411
  this.addTimelineEntry("crew_completed", this.name);
4245
4412
  }
4413
+ /**
4414
+ * Execute a batch of ready tasks concurrently with a bounded worker pool.
4415
+ *
4416
+ * Each task still emits its `task:assigned` and `task:completed` events in
4417
+ * order relative to itself, but events across tasks are interleaved as the
4418
+ * workers settle. At most `concurrency` tasks run at once. If any task throws
4419
+ * (after exhausting retries), no further tasks are started, in-flight tasks
4420
+ * are allowed to settle, and the first error is rethrown so the caller's
4421
+ * error handling (crew:error) behaves identically to the sequential path.
4422
+ */
4423
+ async *processReadyTasksConcurrently(readyTasks, options, eventQueue, concurrency) {
4424
+ let nextIndex = 0;
4425
+ let firstError;
4426
+ const buffer = [];
4427
+ const inFlight = /* @__PURE__ */ new Set();
4428
+ const launch = (task) => {
4429
+ const worker = (async () => {
4430
+ const delegationResult = await this.delegateTask(task, options);
4431
+ buffer.push(
4432
+ this.createEvent({
4433
+ type: "task:assigned",
4434
+ taskId: task.id,
4435
+ agentName: delegationResult.selectedAgent,
4436
+ reason: delegationResult.reason,
4437
+ strategy: this.config.delegationStrategy
4438
+ })
4439
+ );
4440
+ const taskResult = await this.executeTask(task, delegationResult);
4441
+ buffer.push(
4442
+ this.createEvent({
4443
+ type: "task:completed",
4444
+ taskId: task.id,
4445
+ result: taskResult,
4446
+ agentName: delegationResult.selectedAgent,
4447
+ durationMs: taskResult.latencyMs ?? 0
4448
+ })
4449
+ );
4450
+ })().catch((error) => {
4451
+ if (firstError === void 0) {
4452
+ firstError = error;
4453
+ }
4454
+ }).finally(() => {
4455
+ inFlight.delete(worker);
4456
+ });
4457
+ inFlight.add(worker);
4458
+ };
4459
+ const fill = () => {
4460
+ while (inFlight.size < concurrency && nextIndex < readyTasks.length && this.state === "running" && firstError === void 0) {
4461
+ launch(readyTasks[nextIndex++]);
4462
+ }
4463
+ };
4464
+ fill();
4465
+ while (inFlight.size > 0) {
4466
+ await Promise.race(inFlight);
4467
+ while (buffer.length > 0) {
4468
+ yield buffer.shift();
4469
+ }
4470
+ while (eventQueue.length > 0) {
4471
+ yield eventQueue.shift();
4472
+ }
4473
+ fill();
4474
+ }
4475
+ while (buffer.length > 0) {
4476
+ yield buffer.shift();
4477
+ }
4478
+ while (eventQueue.length > 0) {
4479
+ yield eventQueue.shift();
4480
+ }
4481
+ if (firstError !== void 0) {
4482
+ throw firstError;
4483
+ }
4484
+ }
4246
4485
  /**
4247
4486
  * Delegate a task to an agent
4248
4487
  */
@@ -4462,7 +4701,7 @@ ${r.output}`).join("\n\n---\n\n");
4462
4701
  */
4463
4702
  createCheckpoint() {
4464
4703
  return {
4465
- id: (0, import_nanoid4.nanoid)(),
4704
+ id: nanoid(),
4466
4705
  crewId: this.id,
4467
4706
  crewName: this.name,
4468
4707
  timestamp: /* @__PURE__ */ new Date(),
@@ -11,8 +11,8 @@ import {
11
11
  createResearchCrewConfig,
12
12
  createWritingCrew,
13
13
  createWritingCrewConfig
14
- } from "../chunk-TFB7N65B.mjs";
15
- import "../chunk-QMK3HWFX.mjs";
14
+ } from "../chunk-3NMVWRVW.mjs";
15
+ import "../chunk-J5KQSOGT.mjs";
16
16
  export {
17
17
  CodeReviewTasks,
18
18
  CustomerSupportTasks,