@cogitator-ai/swarms

中文文档
0.15.12发布于 2026/10/29MITTypeScriptES Module近 30 天下载 1.1万

Multi-agent swarm coordination for Cogitator

原始使用文档
文档目录25 节
  1. Installation
  2. Quick Start
  3. Features
  4. Agent Roles and Metadata
  5. Strategies
  6. Hierarchical
  7. Round-Robin
  8. Consensus
  9. Pipeline
  10. Debate
  11. Auction
  12. Negotiation
  13. Team
  14. Running Swarms
  15. Pause, Resume, Abort, Reset
  16. Error Handling and Limits
  17. Agent Communication
  18. Message Bus
  19. Blackboard
  20. Built-in Swarm Tools
  21. SwarmAssessor (Automatic Model Selection)
  22. Workflow Integration
  23. Swarm Events
  24. Distributed Execution
  25. License

@cogitator-ai/swarms

Multi-agent swarm coordination for Cogitator. Orchestrate teams of AI agents with eight collaboration strategies, automatic model selection, shared communication primitives, workflow integration and Redis-backed distributed execution.

Installation

pnpm add @cogitator-ai/swarms @cogitator-ai/core

Website docs: Swarms, Strategies, Builder, Communication, Assessment, Distributed.

Quick Start

import { Cogitator, Agent } from '@cogitator-ai/core';
import { SwarmBuilder } from '@cogitator-ai/swarms';

const cogitator = new Cogitator({ llm: { defaultModel: 'ollama/llama3.2' } });
const model = 'ollama/llama3.2';

const swarm = new SwarmBuilder('dev-team')
  .strategy('hierarchical')
  .supervisor(new Agent({ name: 'lead', model, instructions: 'Coordinate the team' }))
  .workers([
    new Agent({ name: 'coder', model, instructions: 'Write code' }),
    new Agent({ name: 'tester', model, instructions: 'Test code' }),
  ])
  .build(cogitator);

const result = await swarm.run({ input: 'Build a REST API for user management' });
console.log(result.output);

Strategies equip agents with the tools they need: the hierarchical supervisor receives delegate_task, check_progress, request_revision and list_workers, consensus voters receive the voting tools, negotiating agents receive the negotiation tools, and the lead and the members of a team receive the task list and mailbox tools. agentTools adds the messaging and blackboard tools to every agent (see Built-in Swarm Tools). Tools an agent already defines with the same name are kept.

Features

  • 8 Coordination Strategies - hierarchical, round-robin, consensus, auction, pipeline, debate, negotiation, team
  • Automatic Model Selection — SwarmAssessor matches models to agent roles
  • Agent Communication — message bus with read tracking, shared blackboard, message:* / blackboard:write events
  • Built-in Tools — messaging, blackboard, delegation, voting and negotiation tools
  • Run Control — per-run timeout, thread ids, lifecycle callbacks, pause/resume/abort with cancellation of in-flight LLM calls
  • Resilience — retry with backoff, failover chains, skip, partial results, circuit breaker
  • Resource Limits — per-run token/cost/time budgets and per-agent caps
  • Workflow Integration — run swarms as DAG workflow nodes
  • Distributed Execution — Redis-backed state and worker nodes from @cogitator-ai/worker

Agent Roles and Metadata

Agents keep their swarm metadata (role, expertise, weight, model lock) in agentMetadata, keyed by agent name. Slot defaults apply automatically: supervisor → role: 'supervisor', workers → role: 'worker', moderator → role: 'moderator', router → role: 'router'.

const swarm = new SwarmBuilder('debate-club')
  .strategy('debate')
  .agents([pro, con])
  .agentMetadata({
    pro: { role: 'advocate', expertise: ['economics'] },
    con: { role: 'critic', weight: 2 },
  })
  .debate({ rounds: 2 })
  .build(cogitator);

Agent names must be unique within a swarm.


Strategies

Hierarchical

A supervisor delegates tasks to workers through the delegate_task tool.

const swarm = new SwarmBuilder('dev-team')
  .strategy('hierarchical')
  .supervisor(lead)
  .workers([frontend, backend, tester])
  .hierarchical({
    maxDelegationDepth: 2, // workers may re-delegate once
    workerCommunication: false, // workers can only message the supervisor
    routeThrough: 'supervisor',
    visibility: 'summary', // supervisor sees the first 500 chars of worker output
  })
  .build(cogitator);

Workers that ran during the supervisor turn are included in result.agentResults. Delegating to yourself or to the supervisor is refused.

Round-Robin

const swarm = new SwarmBuilder('support-team')
  .strategy('round-robin')
  .agents([support1, support2, support3])
  .roundRobin({
    rotation: 'sequential',
    sticky: true,
    stickyKey: (input) => String(input).slice(0, 20),
  })
  .build(cogitator);

With sticky: true a known stickyKey stays with the agent that handled it first; new keys keep rotating. Without stickyKey every run rotates.

Consensus

Agents vote with VOTE: <decision> in their answer or with the cast_vote tool, which voters get automatically together with get_votes, change_vote and get_consensus_status. A decision wins when its share of all eligible voters reaches the threshold and it is not tied; abstentions count against it.

const swarm = new SwarmBuilder('review-board')
  .strategy('consensus')
  .agents([security, performance, ux])
  .consensus({
    threshold: 0.66,
    maxRounds: 3,
    resolution: 'weighted', // 'majority' | 'unanimous' | 'weighted'
    weights: { security: 2 },
    onNoConsensus: 'escalate', // 'fail' | 'supervisor-decides' | 'escalate'
  })
  .build(cogitator);

const result = await swarm.run({ input: 'Approve the new caching layer?' });
console.log(result.votes);

Pipeline

const swarm = new SwarmBuilder('content-pipeline')
  .strategy('pipeline')
  .pipeline({
    stages: [
      { name: 'research', agent: researcher },
      { name: 'draft', agent: writer, gate: true },
      { name: 'edit', agent: editor },
    ],
    gates: {
      draft: {
        condition: (output) => String(output).length > 200,
        onFail: 'retry-previous', // 'abort' | 'skip' | 'goto:<stage>'
        maxRetries: 2,
      },
    },
  })
  .build(cogitator);

const result = await swarm.run({ input: 'Write about vector databases' });
console.log(result.pipelineOutputs);

With new Swarm(cogitator, config) the stages can also be given as the top-level stages field; gates and stageInput still come from pipeline, and different stages in both places are rejected.

Debate

const swarm = new SwarmBuilder('analysis-team')
  .strategy('debate')
  .agents([optimist, skeptic])
  .agentMetadata({ optimist: { role: 'advocate' }, skeptic: { role: 'critic' } })
  .moderator(moderator)
  .debate({ rounds: 3, format: 'structured', maxTokensPerTurn: 400 })
  .build(cogitator);

Turns are labelled with the speaker's name and role ([optimist (advocate)]: ...). synthesisPrompt replaces the moderator's default task, with {topic} and {transcript} filled in. maxTokensPerTurn is the length of a turn's answer: the output limit of a model that does not reason, and the length debaters are asked to keep to. A reasoning model spends its reasoning from the same limit, so a turn it spent thinking (cut off or empty, with little visible text) is run once more with room to reason on top: reasoningTokensPerTurn, 4096, or twice what it reasoned. Set reasoningTokensPerTurn to give that room from the first try; within it the instructions, not the provider, keep the answer short. A model that does not reason keeps the limit as it is, and a turn that called tools is never run again.

Auction

const swarm = new SwarmBuilder('contractor-pool')
  .strategy('auction')
  .agents([contractorA, contractorB])
  .auction({
    bidding: 'capability-match', // agents bid via LLM; or 'custom' with bidFunction
    selection: 'highest-bid', // or 'weighted-random'
    minBid: 0.3,
  })
  .build(cogitator);

Negotiation

Agents negotiate with structured offers through the negotiation tools (make_offer, counter_offer, accept_offer, reject_offer, coalitions, interests). An offer becomes an agreement once every recipient accepted it.

const swarm = new SwarmBuilder('deal-makers')
  .strategy('negotiation')
  .agents([buyer, seller])
  .negotiation({
    maxRounds: 6,
    onDeadlock: 'arbitrate', // 'escalate' | 'supervisor-decides' | 'majority-rules' | 'arbitrate' | 'fail'
    maxOffersPerRound: 2,
    offerTimeout: 120_000,
    turnTimeout: 60_000,
    allowCoalitions: false,
    quorum: 1, // all parties must be part of the agreement
  })
  .build(cogitator);

const result = await swarm.run({ input: 'Agree on price and delivery date' });
console.log(result.negotiationResult?.agreement);

When stagnation is detected, the strategy proposes a mediated compromise as an offer from mediator; agents accept it with accept_offer.

Approval gates (approvalGates) announce each request with the negotiation:approval-required event. A gate with timeout resolves by its timeoutAction; a gate without one waits for your answer. A run timeout or swarm.abort() stops the wait.

import type { NegotiationApprovalRequest } from '@cogitator-ai/types';

swarm.on('negotiation:approval-required', (event) => {
  const { request } = event.data as { request: NegotiationApprovalRequest };
  swarm.respondToApproval(request.id, {
    requestId: request.id,
    decision: 'approved',
    approved: true,
    continueNegotiation: false,
    respondedBy: 'legal-team',
    respondedAt: Date.now(),
  });
});

Team

Agent teams, in the spirit of Claude Code's agent teams: a lead plans the work as a shared task list, members claim or are assigned tasks and work through them, everyone talks through mailboxes, and the lead writes the final answer from the results. The lead is the swarm's supervisor (.lead() in the builder), the members are its workers (.members()).

const swarm = new SwarmBuilder('newsroom')
  .strategy('team')
  .lead(new Agent({ name: 'editor', model, instructions: 'Plan the article and assign the work' }))
  .members([
    new Agent({ name: 'researcher', model, description: 'Finds facts', instructions: 'Research' }),
    new Agent({ name: 'writer', model, description: 'Writes clearly', instructions: 'Write' }),
  ])
  .team({ maxTurnsPerMember: 6, maxConcurrentMembers: 2 })
  .build(cogitator);

const result = await swarm.run({ input: 'Write an article about tides' });
console.log(result.output);
console.log(result.teamResult?.tasks); // every task with its status, owner and result

How a run goes:

  • The lead takes the first turn and creates tasks with create_task (dependsOn makes a task wait for others, assignee gives it to a member) and assign_task. If the request needs no team, it answers at once and the run ends there (stopReason: 'no-tasks').
  • A task is pending, in_progress or completed, the statuses of write_todos. A pending task with unfinished dependencies cannot be claimed, completing a task unblocks the tasks that wait for it, and a member works on one task at a time.
  • A member takes a turn when it has a task: one assigned to it, or with selfClaim the next unassigned one that is not blocked. The task is claimed for it before the turn, in one synchronous step on the blackboard, so two members never get the same task. Unassigned tasks wait while the lead is in a turn, since the lead may still assign them.
  • Each agent has a mailbox. send_message writes to a member, to the lead ("lead") or to everyone ("everyone"), and a message wakes its recipient. Every message is marked with the agent that sent it and comes with a notice that it is from another agent, not from the user, so a teammate's claim of approval is never taken as the user's.
  • The lead gets a turn when messages reach it, and when nobody can go on with the tasks left (for example a task assigned to a member that used its turns). Once every task is completed, or no agent has a reason or a turn left, the lead writes the final answer from the task results.
ToolLeadMemberWhat it does
create_taskyesPuts a task on the list, with dependsOn, assignee and an optional id
assign_taskyesGives a pending task to a member
list_tasksyesyesThe task list with statuses, owners, blockers and results, and what can be taken
claim_taskyesStarts the named task, or the next one the member can take
update_taskyesyesCompletes a task with its result, releases it (pending) or adds a note
send_messageyesyesWrites to a member, lead or everyone
read_inboxyesyesReads the unread messages, each marked with its sender
OptionDefaultDescription
tasks[]Tasks on the list before the lead's first turn (TeamTaskInput[])
selfClaimtrueIdle members take unassigned tasks, without it only assigned tasks are worked on
maxConcurrentMembersresources.maxConcurrency or 4Members working at the same time
maxLeadTurns6Lead turns before the final answer, its first turn included
maxTurnsPerMember8Turns of each member, a member out of turns gives its tasks back to the list
maxTasks50Tasks the list holds
synthesizetrueThe lead writes the final answer, without it the output is the tasks and their results

Every turn spends one of these finite budgets, so a run always ends. result.teamResult holds the tasks, the state of each agent (idle, working, stopped, failed), the turns taken and the stopReason: completed, no-tasks, stalled (nobody could go on) or turn-limit. A member whose turn fails fails the run, unless errorHandling asks for partialResults or onAgentFailure: 'skip': then it is marked failed and its tasks go back to the list. The team strategy runs in-process only, like hierarchical and negotiation.

The task list lives in the blackboard section team and the mailboxes on the message bus. TeamTaskBoard and TeamMailbox work on them directly, for tests or custom strategies, and the team:* events (see Swarm Events) report every change, enough to draw the team live, which Cogitator Studio does.


Running Swarms

const result = await swarm.run({
  input: 'Plan the release',
  threadId: 'release-42', // each agent uses thread `release-42:<agent>`
  timeout: 120_000, // rejects with SwarmTimeoutError and cancels the run
  saveHistory: false,
  context: { project: 'cogitator' },
  onAgentStart: (agent) => console.log('start', agent),
  onAgentComplete: (agent, run) => console.log('done', agent, run.usage.totalTokens),
  onAgentError: (agent, error) => console.error(agent, error.message),
  onMessage: (message) => console.log(`${message.from} → ${message.to}`),
  onEvent: (event) => console.log(event.type),
});

A Swarm instance runs one task at a time; create separate instances for concurrent runs.

A run that times out or fails is cancelled as a whole: in-flight LLM calls are aborted, and work its strategy still has in flight starts no further agents or retries, even after run() has rejected or the next run of the same swarm has begun. Coordinators bind strategy work to its run with runInScope(scope, work) (BaseSwarmCoordinator), so every agent run takes the thread, user and abort signal of the run that started it.

Pause, Resume, Abort, Reset

const running = swarm.run({ input: 'Long task' });

swarm.pause(); // agents wait before their next turn
swarm.resume();
swarm.abort(); // rejects pending turns and cancels in-flight LLM calls

await running.catch(() => {});
await swarm.reset(); // clears abort state, budgets, messages and blackboard

Error Handling and Limits

const swarm = new SwarmBuilder('resilient-team')
  .strategy('round-robin')
  .agents([primary, backup])
  .errorHandling({
    onAgentFailure: 'failover', // 'retry' | 'failover' | 'skip' | 'abort'
    failover: { primary: 'backup' },
    retry: { maxRetries: 3, backoff: 'exponential', initialDelay: 500, maxDelay: 10_000 },
    circuitBreaker: { enabled: true, threshold: 5, resetTimeout: 30_000 },
    partialResults: true, // parallel phases return the agents that succeeded
  })
  .resources({
    maxConcurrency: 4,
    tokenBudget: 100_000, // per run
    costLimit: 5,
    timeout: 300_000,
    perAgent: { maxTokens: 2_000, maxIterations: 5, timeout: 60_000 },
  })
  .build(cogitator);

const usage = swarm.getResourceUsage();

CircuitBreaker and ResourceTracker are exported for standalone use.

A turn whose agent run pauses for tool approvals (requiresApproval) fails with an AgentRunPausedError from @cogitator-ai/core, carrying the waiting calls and the checkpoint, instead of passing the pre-tool text on as the answer. It is never retried, skipped or failed over, and does not trip the circuit breaker.


Agent Communication

Message Bus

await swarm.messageBus.send({
  swarmId: swarm.id,
  from: 'operator',
  to: 'coder',
  type: 'notification',
  content: 'Use TypeScript strict mode',
});

Unread messages are injected into the recipient's next turn exactly once (message:received event). maxMessagesPerTurn limits how many messages an agent may send per turn.

Blackboard

const swarm = new SwarmBuilder('research-team')
  .strategy('hierarchical')
  .supervisor(lead)
  .workers([researcher])
  .messaging({ enabled: true, maxMessagesPerTurn: 5 })
  .blackboardConfig({ enabled: true, sections: { findings: [] }, trackHistory: true })
  .observability({ messageLogging: true, blackboardLogging: true })
  .build(cogitator);

swarm.blackboard.subscribe('findings', (data, writer) => console.log(writer, data));

Built-in Swarm Tools

Enable agentTools to give every agent the messaging and blackboard tools, bound to the swarm's own bus and blackboard (local swarms only; rejected when distributed or when the bus / blackboard is disabled):

const swarm = new SwarmBuilder('research-team')
  .strategy('round-robin')
  .agents([researcher, writer])
  .agentTools({ messaging: true, blackboard: true })
  .build(cogitator);

Consensus voters get the voting tools automatically. For custom strategies and coordinators, the factories build any tool set:

import { createSwarmTools, createStrategyTools, type SwarmToolContext } from '@cogitator-ai/swarms';

const context: SwarmToolContext = {
  coordinator, // the swarm coordinator (SwarmCoordinatorInterface)
  blackboard: swarm.blackboard,
  messageBus: swarm.messageBus,
  events: swarm.events,
  agentName: 'coder',
  swarmId: swarm.id,
};

const allTools = createSwarmTools(context); // messaging, blackboard, delegation, voting, negotiation
const hierarchicalTools = createStrategyTools('hierarchical', context);
FactoryTools
createMessagingToolssend_message (optional waitForReply), read_messages (marks returned messages read), broadcast_message, reply_to_message
createBlackboardToolsread_blackboard, write_blackboard (merge extends arrays / merges objects), append_blackboard, list_blackboard_sections, get_blackboard_history
createDelegationToolsdelegate_task, check_progress, request_revision, list_workers
createVotingToolscast_vote, get_votes, change_vote, get_consensus_status
createNegotiationToolsmake_offer, counter_offer, accept_offer, reject_offer, get_negotiation_status, get_current_offers, propose_coalition, join_coalition, declare_interests
createTeamToolscreate_task, assign_task, list_tasks, claim_task, update_task, send_message, read_inbox (teamToolsFor(tools, role) picks the lead's or a member's)

Messaging tools created through createSwarmTools/createStrategyTools enforce the hierarchical communication policy (createHierarchyMessageAuthorizer).


SwarmAssessor (Automatic Model Selection)

const swarm = new SwarmBuilder('smart-team')
  .strategy('hierarchical')
  .supervisor(lead)
  .workers([coder, analyst])
  .agentMetadata({ lead: { locked: true }, coder: { expertise: ['code'] } })
  .withAssessor({
    mode: 'rules',
    preferLocal: true,
    minCapabilityMatch: 0.3,
    maxCostPerRun: 0.5,
    enabledProviders: ['ollama', 'openai'],
  })
  .build(cogitator);

const preview = await swarm.dryRun({ input: 'Build a recommendation engine' });
for (const a of preview.assignments) {
  console.log(`${a.agentName}: ${a.assignedModel} (score ${a.score})`);
}

await swarm.run({ input: 'Build a recommendation engine' });
console.log(swarm.getLastAssessment()?.assignments);

Assigned models are provider-qualified (e.g. ollama/llama3.2:3b). Unlocked agents are replaced by clones running the assigned model; locked agents keep theirs.

mode: 'rules' (default) analyzes the task with keyword rules. 'ai' lets the assessorModel (default: the Cogitator's default model) analyze it; 'hybrid' adds every hard requirement the rules detect. Both fall back to the rules with a warning when the model cannot run. Inside a Swarm only cloud models whose provider the Cogitator can route (API key configured) are offered; standalone, pass the Cogitator to createAssessor(config, cogitator) for the same behaviour.


Workflow Integration

import { WorkflowBuilder, WorkflowExecutor } from '@cogitator-ai/workflows';
import { swarmNode, parallelSwarmsNode } from '@cogitator-ai/swarms';

const workflow = new WorkflowBuilder<{ document: string; analysis?: unknown }>('analysis-flow')
  .initialState({ document: '' })
  .addNode(
    'analyze',
    swarmNode(analysisSwarm, {
      inputMapper: (state) => state.document,
      stateMapper: (result) => ({ analysis: result.output }),
    })
  )
  .build();

const result = await new WorkflowExecutor(cogitator).execute(workflow, {
  document: 'Analyze this...',
});

conditionalSwarmNode(swarm, condition, options) and parallelSwarmsNode([{ swarm, key }], merge) are also available. Pass a SwarmConfig instead of a Swarm to create (and close) a fresh swarm per execution. The nodes pass the workflow run's abort signal to the swarm, so a node timeout, pause or cancel stops it and its agent turns. Outside workflows, swarm.run({ input, signal }) takes a signal the same way.


Swarm Events

swarm.on('agent:complete', (event) => console.log(event.agentName));
swarm.once('swarm:complete', () => console.log('done'));
const unsubscribe = swarm.on('*', (event) => console.log(event.type));
unsubscribe();

Subscriptions survive the coordinator rebuild that happens after model assessment.

EventDescription
swarm:start / swarm:complete / swarm:errorRun lifecycle
swarm:paused / swarm:resumed / swarm:aborted / swarm:resetControl actions
agent:start / agent:complete / agent:errorAgent turns
message:sent / message:receivedBus messages sent / delivered to an agent's turn
blackboard:writeSection written or deleted
assessor:completeModel assessment finished
consensus:*, debate:*, auction:*, pipeline:*, round-robin:assigned, negotiation:*Strategy progress
team:start / team:completeTeam run lifecycle, with the stop reason
team:member-started / team:member-finishedA turn of the lead or a member, with its reason
team:task-created / team:task-assigned / team:task-claimed / team:task-updated / team:task-completedTask list changes, each with the task as it is now
team:message-sentA message written into mailboxes

The data of each team:* event is typed by TeamEventMap from @cogitator-ai/types:

import type { TeamEventMap } from '@cogitator-ai/types';

swarm.on('team:task-completed', (event) => {
  const { task, unblocked } = event.data as TeamEventMap['team:task-completed'];
  console.log(`${task.id} done by ${task.owner}, unblocks ${unblocked.join(', ')}`);
});

Distributed Execution

With distributed.enabled, the swarm keeps its message bus, blackboard and events in Redis and dispatches every agent turn as a job. Worker nodes from @cogitator-ai/worker execute the turns and hand the results back.

const swarm = new SwarmBuilder('distributed-team')
  .strategy('pipeline')
  .pipeline({
    stages: [
      { name: 'draft', agent: writer },
      { name: 'review', agent: reviewer },
    ],
  })
  .distributed({
    enabled: true,
    queue: 'swarm-agent-jobs',
    timeout: 300_000,
    redis: { url: 'redis://localhost:6379', keyPrefix: 'swarm' },
    retry: { maxRetries: 2, backoff: 'exponential', initialDelay: 1000 },
    cleanupAfter: 3_600_000,
  })
  .build(cogitator);

const result = await swarm.run({ input: 'Write release notes' });
await swarm.close();

Worker node:

import { Cogitator } from '@cogitator-ai/core';
import { DistributedSwarmWorker } from '@cogitator-ai/worker';

const worker = new DistributedSwarmWorker({
  redis: { url: 'redis://localhost:6379' }, // the same Redis as distributed.redis
  keyPrefix: 'swarm', // must match distributed.redis.keyPrefix
  queue: 'swarm-agent-jobs', // must match distributed.queue
  concurrency: 4,
  cogitator: new Cogitator({ llm: { defaultModel: 'ollama/llama3.2' } }),
  tools: [searchTool, calculatorTool], // implementations of tools the agents reference
});

await worker.start();
process.on('SIGTERM', () => void worker.stop());

retry re-dispatches jobs that fail on a worker or time out (defaults: 3 retries, exponential backoff from 1000 ms up to 30000 ms, without it nothing is re-dispatched), a timed-out job may still be running, so its turn can run twice. cleanupAfter expires the swarm's Redis state after close() (default one hour, 0 deletes it at once). workerConcurrency is deprecated - set concurrency on the worker. The swarm's errorHandling (retry, failover), budgets and circuit breaking work the same as for local swarms: each turn carries the whole agent in the agent wire format of @cogitator-ai/core (response format, reasoning, stop sequences, timeout and the rest), and comes back with the cost, duration and flags (truncated, blocked) the worker measured. RedisMessageBus, RedisBlackboard and RedisSwarmEventEmitter are exported for direct use.

distributed.redis is a RedisConnectionConfig (url, host, port, username, password, db, tls, cluster.nodes) plus keyPrefix, the same config the worker takes. The url is read first (rediss:// turns on TLS) and the explicit fields win over it. With cluster the swarm and its workers connect to a Redis Cluster, and the url and fields give only the credentials and TLS.

Keys carry Redis Cluster hash tags, with literal braces: the queue is <keyPrefix>:jobs:{<queue>} and the swarm's state keys are <keyPrefix>:{<swarmId>}:..., so in a cluster each group sits in one slot. Earlier versions used keys without the braces, so upgrade coordinators and workers together.

The queue is reliable. A worker moves each turn with BLMOVE (Redis 6.2 or newer) from the queue to its own list <queue key>:processing:<workerId> and takes it off once the turn is done. It keeps a heartbeat key <queue key>:heartbeat:<workerId> (expiring after three heartbeatIntervals, 5000 ms by default) and is listed in the set <queue key>:workers. On start and on every beat, a worker moves the turns of workers whose heartbeat is gone back to the head of the queue, so a crashed worker loses no turns. A worker also checks its own list on every beat: a turn on it that the worker does not run at two beats in a row, such as one a BLMOVE moved while a dropped connection lost its reply, goes back to the head of the queue and is reported with the worker's own id. A worker silent for three intervals counts as gone, so a turn on a stalled worker can run twice.

The worker keeps each result under the job's stateKeys.result (<keyPrefix>:{<swarmId>}:result:<jobId>) for resultTtl ms, which the coordinator sets to the larger of timeout and cleanupAfter, and then publishes it. The coordinator reads the stored result when a turn times out, when either of its connections reconnects and every few seconds, so a result published while it reconnected is not lost. A result the worker cannot keep under its key is still published. A worker skips a job whose result is already there, and the coordinator deletes the stored result before it re-dispatches a retry.

The building blocks are exported too: swarmJobQueueKey and swarmQueueKeys give the queue keys, deliverSwarmJobResult (with DEFAULT_SWARM_RESULT_TTL) hands a result back the way workers do, and resolveRedisOptions, clusterNodeOptions, createSwarmRedis, duplicateSwarmRedis, scanSwarmKeys and closeSwarmRedis turn a RedisConnectionConfig into ioredis clients (SwarmRedis, a Redis or Cluster) and work with them on both.


License

MIT

版本与发布记录

@cogitator-ai/swarms 共发布 114 个版本,首次发布于 2025/12/31;过去 12 个月发布了 114 个版本。

版本发布日期距今
0.15.12latest2026/10/2912 天前
0.15.112026/10/2912 天前
0.15.102026/10/2912 天前
0.15.92026/10/2912 天前
0.15.82026/10/2912 天前
0.15.72026/10/2812 天前

关于 @cogitator-ai/swarms 的常见问题

@cogitator-ai/swarms 是什么?

Multi-agent swarm coordination for Cogitator

如何安装 @cogitator-ai/swarms?

在项目目录运行 npm install @cogitator-ai/swarms,或使用 pnpm add / yarn add / bun add。

@cogitator-ai/swarms 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cogitator-ai/swarms 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@cogitator-ai/swarms 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cogitator-ai/swarms 可以商用吗?

@cogitator-ai/swarms 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cogitator-ai/swarms 的下载量有多少?

根据 npm 官方下载统计,@cogitator-ai/swarms 在 2026/10/11 – 2026/11/09 这 30 天内被下载 11,347 次,日均约 378 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cogitator-ai/swarms 还在维护吗?

最新版本 0.15.12 发布于 2026/10/29(12 天前);至今共发布 114 个版本,其中过去 12 个月发布了 114 个;首次发布于 2025/12/31。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。