rcrewai 0.4.0 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f742fcf06518c80cbf29191d0eff275830ee618c9b896c3d443258b06aa120ff
4
- data.tar.gz: 5cc9c03182d0bd80d73d99edb08f2267252684f64a23da1626d2d61e0abe1683
3
+ metadata.gz: fb90e26000ddf4a2907b06150fdc87b1707fc701c6c61ba35db33339ed6f38d4
4
+ data.tar.gz: ba3435eb1918be328ce65faf2c3000553833b09778eb3b06f2a6191cae31aab4
5
5
  SHA512:
6
- metadata.gz: 0c32e4110a5bbabac9b120262e2ebe0e86b0c58c3b4213a11214efcff647024d9714fcee12934f4b734c9f64184e1f802d82b97ec50e5dc7ceab424c4cec38f1
7
- data.tar.gz: 8a678ae53008c7c6a73cf365b460b80989da05f22eb646cf3a9126028a0d6dd220e6af75ef4dee80c02d73e69b536fb3d2b7c23f827e929078b76ed450d8f1ce
6
+ metadata.gz: 992ac3d7368cb7690f11294b78fe876fcea29d48cffd001a355471a351c22c321563fbd390a0688951be6bcbd0f177322509e59cdd19cf8073e228784d96b503
7
+ data.tar.gz: 92e7db7609d4503693396f85735fd48633cb5204a34d2431e57ffcb7c758e693bff5b1282ed716899f4242bd9a26b0483f278c991dedb13b21d05894a59b7105
data/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-07-06
11
+
12
+ Replaces the placeholder agent memory with a **cognitive memory** system —
13
+ semantic recall (embeddings + cosine), optional SQLite persistence, and four
14
+ memory types. This is the one area where CrewAI advanced past what the gem
15
+ originally ported. Backward compatible: the `Memory` public API is unchanged and
16
+ the zero-config default behaves as before.
17
+
18
+ ### Added
19
+ - Cognitive memory: `RCrewAI::Memory` is now a semantic, optionally-persistent, multi-type memory system, replacing the previous word-overlap placeholder. It composes four memory types — `ShortTermMemory` (recent executions, capped), `LongTermMemory` (durable, deduped insights), `EntityMemory` (facts about entities seen in work), and `ToolMemory` (tool-call history) — behind the original `Memory` public API.
20
+ - Semantic recall: pass `Agent.new(memory: { embedder: RCrewAI::Knowledge::Embedder.new })` to recall conceptually related past work via embeddings + cosine similarity. Without an embedder, recall falls back to lexical (word-overlap) similarity — and embedding failures fall back gracefully, so memory never breaks execution.
21
+ - Persistent memory: `RCrewAI::Memory::SqliteStore` persists memories to SQLite (vectors packed as floats, metadata as JSON) so recall survives restarts. Default store is `InMemoryStore` (volatile). The store interface is pluggable.
22
+ - Memory scoping: each agent's memory is scoped to its name by default, so agents sharing a persistent store don't cross-read; override via `memory: { scope: ... }`.
23
+ - `RCrewAI::Similarity` — shared cosine + lexical similarity helpers (extracted from `Knowledge::Store`, now used by both Knowledge and Memory).
24
+ - `sqlite3` added as a runtime dependency (required lazily; only needed for `SqliteStore`).
25
+
26
+ ### Changed
27
+ - `Agent.new(memory:)` accepts a pre-built `Memory`, an options hash (`{ embedder:, store:, scope:, short_term_limit: }`), or nothing (zero-config default, unchanged behavior).
28
+
29
+ ## [0.5.0] - 2026-07-03
30
+
31
+ Polish release completing the roadmap backlog: crew lifecycle hooks, batch
32
+ execution, rate limiting, per-agent reasoning, context-window management, and
33
+ multimodal image input. All additive — existing code runs unchanged.
34
+
35
+ ### Added
36
+ - Crew lifecycle hooks: `Crew#before_kickoff` and `Crew#after_kickoff` register callbacks that run before/after execution. A `before_kickoff` hook receives the inputs hash (passed via `crew.execute(inputs:)`) and may transform it; an `after_kickoff` hook receives the result and may transform it. Multiple hooks run in registration order. The (possibly transformed) inputs are exposed on `Crew#last_inputs`. (#15)
37
+ - `Crew#kickoff_for_each(inputs:)` runs the crew once per input set and returns one result per input, in order. Runs are isolated — each execution starts from only its own inputs. (#16)
38
+ - Rate limiting: `Agent.new(max_rpm:)` throttles the agent's LLM calls to the given requests-per-minute using a thread-safe rolling-window `RCrewAI::RateLimiter`. The agent's client is transparently wrapped (`RateLimiter::ThrottledClient`) so every `chat` acquires a slot first; `max_rpm` nil/0 means unlimited. (#17)
39
+ - Reasoning: `Agent.new(reasoning: true)` runs a reasoning/planning pass before answering — the LLM drafts a short plan for the task, which is injected into the answer prompt and surfaced on the result hash as `:reasoning` (without polluting `task.result`). Bounded by `max_reasoning_attempts` (default 3), retrying if the model returns empty output; if every attempt is empty, execution proceeds without a plan. Off by default. (#18)
40
+ - Context-window management: `Agent.new(respect_context_window: true)` trims the message history to fit the model's context window before each LLM call, dropping the oldest non-system messages while always keeping system messages and the latest message. The new `RCrewAI::ContextWindow` module provides the token estimate (chars/4 heuristic), a per-model window-size table, and the `fit` trimmer. Off by default. (#19)
41
+ - Multimodal input: `Task.new(attachments:)` accepts image attachments (`{ type: :image, url: '...' }` or `{ type: :image, path: '...' }`). When a task has attachments, the agent builds an OpenAI-style multimodal user message (text + `image_url` parts); local files are base64-encoded into data URLs with a mime type inferred from the extension. Supported on OpenAI/Azure; other providers raise a clear `Multimodal::UnsupportedProviderError`. The new `RCrewAI::Multimodal` module builds the content parts. (#20)
42
+
10
43
  ## [0.4.0] - 2026-07-03
11
44
 
12
45
  This release closes the feature-parity gap with the modern CrewAI framework,
@@ -165,7 +198,9 @@ output, guardrails, planning, and training/testing. See `ROADMAP.md`.
165
198
  - CLI usage documentation
166
199
  - Real-world use cases and examples
167
200
 
168
- [Unreleased]: https://github.com/gkosmo/rcrewAI/compare/v0.4.0...HEAD
201
+ [Unreleased]: https://github.com/gkosmo/rcrewAI/compare/v0.6.0...HEAD
202
+ [0.6.0]: https://github.com/gkosmo/rcrewAI/compare/v0.5.0...v0.6.0
203
+ [0.5.0]: https://github.com/gkosmo/rcrewAI/compare/v0.4.0...v0.5.0
169
204
  [0.4.0]: https://github.com/gkosmo/rcrewAI/compare/v0.3.0...v0.4.0
170
205
  [0.3.0]: https://github.com/gkosmo/rcrewAI/compare/v0.1.0...v0.3.0
171
206
  [0.1.0]: https://github.com/gkosmo/rcrewAI/releases/tag/v0.1.0
data/README.md CHANGED
@@ -13,7 +13,7 @@ RCrewAI is a Ruby implementation of the CrewAI framework, allowing you to create
13
13
  - **🤖 Intelligent Agents**: AI agents with reasoning loops, memory, and tool usage capabilities
14
14
  - **🔗 Multi-LLM Support**: OpenAI, Anthropic (Claude), Google (Gemini), Azure OpenAI, and Ollama
15
15
  - **🛠️ Rich Tool Ecosystem**: Web search, file operations, SQL, email, code execution, PDF processing, and custom tools
16
- - **🧠 Agent Memory**: Short-term and long-term memory for learning from past executions
16
+ - **🧠 Cognitive Memory**: Semantic recall (embeddings + cosine) with optional SQLite persistence and short-term/long-term/entity/tool memory types
17
17
  - **🤝 Human-in-the-Loop**: Interactive approval workflows, human guidance, and collaborative decision making
18
18
  - **⚡ Advanced Task System**: Dependencies, retries, async/concurrent execution, and context sharing
19
19
  - **🏗️ Hierarchical Teams**: Manager agents that coordinate and delegate tasks to specialist agents
@@ -263,6 +263,88 @@ crew.test(n_iterations: 5)
263
263
  # => { iterations: 5, scores: [...], average_score: 92.0 }
264
264
  ```
265
265
 
266
+ ## 🪝 Kickoff Hooks & Batch Runs
267
+
268
+ Run setup/teardown around a crew, and batch it over many inputs:
269
+
270
+ ```ruby
271
+ crew.before_kickoff { |inputs| inputs.merge(started_at: Time.now) } # may transform inputs
272
+ crew.after_kickoff { |result| notify(result); result } # may transform result
273
+
274
+ crew.execute(inputs: { topic: 'ruby' })
275
+ crew.last_inputs # => the (possibly transformed) inputs the run used
276
+
277
+ # Batch: run the crew once per input set, results returned in order.
278
+ results = crew.kickoff_for_each(inputs: [
279
+ { topic: 'ruby' },
280
+ { topic: 'python' }
281
+ ])
282
+ ```
283
+
284
+ ## ⏱️ Rate Limiting
285
+
286
+ Cap an agent's LLM calls to stay under provider limits. Calls beyond the cap
287
+ block until the rolling 60-second window frees up:
288
+
289
+ ```ruby
290
+ agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...', max_rpm: 20)
291
+ ```
292
+
293
+ The limiter (`RCrewAI::RateLimiter`) is thread-safe, so it holds under async
294
+ execution. `max_rpm: nil` (the default) or `0` means unlimited.
295
+
296
+ ## 🧠 Reasoning
297
+
298
+ Have an agent think through a plan before answering. The reasoning trace is
299
+ surfaced on the result and does not pollute `task.result`:
300
+
301
+ ```ruby
302
+ agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...',
303
+ reasoning: true, max_reasoning_attempts: 3)
304
+
305
+ result = agent.execute_task(task)
306
+ result[:reasoning] # => the plan the agent drafted before answering
307
+ result[:content] # => the final answer
308
+ ```
309
+
310
+ Off by default. If the reasoning pass keeps returning empty output past
311
+ `max_reasoning_attempts`, the agent proceeds without a plan.
312
+
313
+ ## 🪟 Context Window Management
314
+
315
+ Keep long tool-use loops or large injected context from overflowing the model's
316
+ context window. When enabled, the oldest non-system messages are dropped to fit
317
+ before each LLM call (system messages and the latest message are always kept):
318
+
319
+ ```ruby
320
+ agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...',
321
+ respect_context_window: true)
322
+ ```
323
+
324
+ Window sizes come from `RCrewAI::ContextWindow` (with a conservative default for
325
+ unknown models); headroom for the response is reserved from `max_tokens`. Off by
326
+ default.
327
+
328
+ ## 🖼️ Multimodal Input
329
+
330
+ Pass images to a vision-capable model via task attachments. Local files are
331
+ base64-encoded automatically; URLs pass through:
332
+
333
+ ```ruby
334
+ RCrewAI.configure { |c| c.llm_provider = :openai; c.openai_model = 'gpt-4o' }
335
+
336
+ task = RCrewAI::Task.new(
337
+ name: 'describe', description: 'What is in this chart?', agent: agent,
338
+ attachments: [
339
+ { type: :image, path: 'chart.png' },
340
+ { type: :image, url: 'https://example.com/photo.jpg' }
341
+ ]
342
+ )
343
+ ```
344
+
345
+ Supported on OpenAI and Azure; other providers raise a clear error when
346
+ attachments are present.
347
+
266
348
  ## 📚 Knowledge (RAG)
267
349
 
268
350
  Ground agents in your own documents. Sources are chunked, embedded, and stored
@@ -292,6 +374,31 @@ Embeddings default to OpenAI's `text-embedding-3-small`; pass a custom
292
374
  `embedder:` (anything responding to `embed(texts)`) or vector store to swap the
293
375
  backend.
294
376
 
377
+ ## 🧠 Cognitive Memory
378
+
379
+ Agents remember what they've done and recall it semantically on future tasks.
380
+ Memory is zero-config by default (in-memory, lexical recall); add an embedder
381
+ for semantic recall and a SQLite store for persistence:
382
+
383
+ ```ruby
384
+ embedder = RCrewAI::Knowledge::Embedder.new
385
+ store = RCrewAI::Memory::SqliteStore.new(path: '~/.rcrewai/memory.db')
386
+
387
+ agent = RCrewAI::Agent.new(
388
+ name: 'engineer', role: '...', goal: '...',
389
+ memory: { embedder: embedder, store: store } # both optional
390
+ )
391
+ ```
392
+
393
+ - **Semantic recall** — with an embedder, an agent recalls conceptually related
394
+ past work even when the wording differs (falls back to word-overlap without one).
395
+ - **Persistence** — a `SqliteStore` makes memory survive restarts.
396
+ - **Memory types** — `agent.memory.short_term` / `long_term` / `entity` / `tool`.
397
+ - **Scoping** — memory is scoped per agent so a shared store doesn't cross-read.
398
+
399
+ Memory is best-effort: embedding failures fall back to lexical similarity, so it
400
+ never breaks agent execution.
401
+
295
402
  ## 🌊 Flows
296
403
 
297
404
  Beyond crews, RCrewAI has **Flows** — an event-driven workflow engine for
data/ROADMAP.md CHANGED
@@ -16,12 +16,10 @@ pricing.
16
16
 
17
17
  Since CrewAI's `1.0`, the framework grew a second pillar (**Flows**) plus
18
18
  **Knowledge (RAG)**, **Guardrails**, **structured output**, **Planning**, and
19
- **Training/Testing**. As of the `[Unreleased]` changes, RCrewAI now implements
20
- all of these — see the matrix below. Only backlog polish items remain.
19
+ **Training/Testing**. RCrewAI now implements all of these see the matrix below.
21
20
 
22
- **Status: all milestone issues (#5–#12) are complete.** The remaining backlog
23
- covers smaller polish items (reasoning, rate-limiting, batch kickoff, kickoff
24
- hooks, multimodal).
21
+ **Status: complete.** All milestone issues (#5–#12) shipped in v0.4.0, and all
22
+ backlog items (#15–#20) shipped in v0.5.0. There is no outstanding roadmap work.
25
23
 
26
24
  ## Parity matrix
27
25
 
@@ -42,7 +40,7 @@ hooks, multimodal).
42
40
  | Flows (`start`/`listen`/`router`) | ✅ | ✅ (#11) | ✅ done |
43
41
  | Flow state + persistence | ✅ | ✅ (#11) | ✅ done |
44
42
  | Training / Testing | ✅ | ✅ (#12) | ✅ done |
45
- | Reasoning, rate-limiting, batch kickoff | ✅ | | backlog |
43
+ | Reasoning, rate-limiting, batch kickoff, hooks, context window, multimodal | ✅ | (#15–#20) | done |
46
44
 
47
45
  ## Milestones (highest leverage first)
48
46
 
@@ -78,7 +76,14 @@ The flagship. A Ruby DSL mirroring CrewAI Flows:
78
76
  - `crew.train(n_iterations:, filename:)` capturing human feedback.
79
77
  - `crew.test(n_iterations:, model:)` scoring runs.
80
78
 
81
- ### Backlog
82
- Per-agent reasoning (`reasoning:`, `max_reasoning_attempts:`), `max_rpm`
83
- rate-limiting, `respect_context_window`, `kickoff_for_each` batch execution,
84
- `before_kickoff` / `after_kickoff` hooks, multimodal agents.
79
+ ### Backlog — ✅ all complete
80
+
81
+ Formerly polish items with no set version; all shipped in the `[Unreleased]`
82
+ changes (see CHANGELOG):
83
+
84
+ - [#15](https://github.com/gkosmo/rcrewAI/issues/15) — `before_kickoff` / `after_kickoff` lifecycle hooks ✅
85
+ - [#16](https://github.com/gkosmo/rcrewAI/issues/16) — `kickoff_for_each` batch execution ✅
86
+ - [#17](https://github.com/gkosmo/rcrewAI/issues/17) — `max_rpm` rate limiting ✅
87
+ - [#18](https://github.com/gkosmo/rcrewAI/issues/18) — per-agent reasoning (`reasoning:`, `max_reasoning_attempts:`) ✅
88
+ - [#19](https://github.com/gkosmo/rcrewAI/issues/19) — `respect_context_window` history trimming ✅
89
+ - [#20](https://github.com/gkosmo/rcrewAI/issues/20) — multimodal agents (image/file inputs) ✅
@@ -0,0 +1,118 @@
1
+ # Cognitive Memory: Semantic, Persistent, Multi-Type Agent Memory
2
+
3
+ **Date:** 2026-07-06
4
+ **Status:** Approved design (pending implementation)
5
+ **Target version:** `rcrewai` 0.6.0 (current is 0.5.0)
6
+ **Scope:** Replace the placeholder `RCrewAI::Memory` with a cognitive memory system modeled on CrewAI's memory taxonomy — short-term (semantic recent recall), long-term (persistent insights), entity memory, and tool-usage memory — backed by embeddings and a persistent SQLite vector store. No new external dependencies; reuses the in-repo `Knowledge::Embedder` and cosine-search infrastructure.
7
+
8
+ ---
9
+
10
+ ## Motivation
11
+
12
+ The current `RCrewAI::Memory` is a placeholder. It matches "relevant" past executions with word-overlap similarity (`common_words / total_words`) plus a hardcoded keyword/stopword list and a `classify_task_type` that greps the description for words like "research" or "write". Nothing is embedded; nothing is persisted; everything is lost when the process exits. It is the weakest module in the codebase and it undercuts the framework's core promise — agents that learn from what they've done.
13
+
14
+ Meanwhile CrewAI has advanced *past* the version this project ported: its 2026 "cognitive memory" work adds semantic recall, distinct memory types (short-term, long-term, entity), and persistence. This is genuine parity work, not gold-plating — and the infrastructure to do it well already exists in-repo (`Knowledge::Embedder`, cosine `Knowledge::Store`), so we compose rather than build from scratch.
15
+
16
+ ## Goals
17
+
18
+ 1. **Semantic recall.** Replace word-overlap with embedding-based similarity so an agent recalls conceptually related past work, not just keyword-overlapping work.
19
+ 2. **Persistence.** Memory survives process restarts via a SQLite-backed vector store (no external service).
20
+ 3. **Memory types.** Model CrewAI's taxonomy: short-term, long-term, entity, and tool-usage memory, each with clear write/read semantics.
21
+ 4. **Backward compatibility.** The existing `Memory` public API (`add_execution`, `add_tool_usage`, `relevant_executions`, `tool_usage_for`, `clear_*!`, `stats`) keeps working, so `Agent` and the runners need no changes to function.
22
+ 5. **No new hard dependencies.** SQLite via Ruby's stdlib-adjacent `sqlite3` gem (already common in Ruby projects) — but the store is pluggable, and the default remains in-memory so the gem works with zero setup.
23
+
24
+ ## Non-goals
25
+
26
+ - External vector databases (Chroma/Qdrant/pgvector). The pluggable store interface leaves room for them later; we ship SQLite + in-memory.
27
+ - Reranking, query rewriting, or summarization of memories (CrewAI has some of this; it's a follow-up).
28
+ - Multi-tenant / shared cross-agent memory servers.
29
+
30
+ ## Decisions captured during brainstorming
31
+
32
+ | # | Decision | Choice |
33
+ |---|----------|--------|
34
+ | 1 | Similarity mechanism | Embeddings + cosine, reusing `Knowledge::Embedder` and the cosine math already in `Knowledge::Store`. |
35
+ | 2 | Persistence | Pluggable vector store; ship `InMemoryStore` (default) and `SqliteStore`. |
36
+ | 3 | Memory taxonomy | Four types: `ShortTermMemory`, `LongTermMemory`, `EntityMemory`, `ToolMemory`. |
37
+ | 4 | Backward compat | Keep the `Memory` facade and its current method signatures; delegate internally to the new types. |
38
+ | 5 | Default behavior | Zero-config: in-memory store, embeddings only if an embedder is available/keyed; graceful fallback to the current lexical similarity when no embedder. |
39
+ | 6 | Embedding failures | Never fatal. If embedding fails (no key, network), fall back to lexical similarity so agents still run. |
40
+ | 7 | Namespacing | Memories are scoped by agent (role/name) so one agent's memory doesn't leak into another, matching CrewAI's per-role collections. |
41
+
42
+ ## Architecture
43
+
44
+ ```
45
+ RCrewAI::Memory (facade — preserves today's public API)
46
+ ├── ShortTermMemory recent executions, semantic recall, capped, volatile-by-default
47
+ ├── LongTermMemory durable insights from successful executions, persistent
48
+ ├── EntityMemory facts about entities (people, systems, concepts) extracted from work
49
+ └── ToolMemory tool-call history + outcomes (replaces @tool_usage)
50
+
51
+ Each memory type holds:
52
+ - a VectorStore (InMemoryStore | SqliteStore) ← persistence + search
53
+ - an Embedder (Knowledge::Embedder | nil) ← semantic vectors
54
+ - a lexical fallback (current word-overlap) ← when no embedder
55
+ ```
56
+
57
+ ### Storage: `Memory::VectorStore`
58
+
59
+ A small interface (mirrors `Knowledge::Store` so they can converge later):
60
+
61
+ ```ruby
62
+ store.add(id:, text:, vector:, metadata:) # upsert a record
63
+ store.search(vector, k:, scope:) # cosine top-k, filtered by scope
64
+ store.all(scope:) # enumerate (for stats / lexical fallback)
65
+ store.delete(scope:) # clear a scope
66
+ ```
67
+
68
+ - **`InMemoryStore`** — array of records; cosine in Ruby (lift the existing private cosine out of `Knowledge::Store` into a shared `Similarity` helper). Default.
69
+ - **`SqliteStore`** — one row per memory: `id, scope, type, text, vector (blob), metadata (json), created_at`. Vectors stored as packed floats (`Array#pack('e*')`). Cosine computed in Ruby over candidate rows filtered by `scope`/`type` (fine for the thousands-of-memories scale agents produce; a real ANN index is a later optimization). Opened at a configurable path (default `~/.rcrewai/memory.db` or `:memory:`).
70
+
71
+ ### Embeddings
72
+
73
+ Reuse `Knowledge::Embedder`. The memory system takes an optional `embedder:`; when present, `add_*` embeds the text and stores the vector, and recall embeds the query. When absent (no key, or explicitly disabled), the store keeps `vector: nil` and recall falls back to the current lexical similarity over `store.all`. This keeps the zero-config path working.
74
+
75
+ ### The four memory types
76
+
77
+ - **ShortTermMemory** — every execution is written here; recall returns the top-k semantically similar recent items. Capped (default 100) and, by default, uses the in-memory store (volatile). This is the direct upgrade of today's `@short_term` + `relevant_executions`.
78
+ - **LongTermMemory** — successful executions promote a distilled "insight" record (task type, what worked, result summary) into a persistent store, deduped by similarity so we don't store near-identical insights repeatedly. Upgrade of today's `@long_term`.
79
+ - **EntityMemory** — optional lightweight entity extraction (heuristic first: capitalized noun phrases / quoted terms; pluggable LLM extractor later) so agents accumulate facts about recurring entities. New capability.
80
+ - **ToolMemory** — replaces `@tool_usage`; same API (`add_tool_usage`, `tool_usage_for`) but persistable and searchable.
81
+
82
+ ### Facade: `RCrewAI::Memory`
83
+
84
+ Keeps today's signatures, delegating to the types:
85
+
86
+ ```ruby
87
+ Memory.new(embedder: nil, store: nil, scope: nil, short_term_limit: 100)
88
+
89
+ add_execution(task, result, execution_time) # -> ShortTerm + (if success) LongTerm + Entity
90
+ add_tool_usage(tool_name, params, result) # -> ToolMemory
91
+ relevant_executions(task, limit = 3) # -> semantic recall across Short+Long, formatted string|nil
92
+ tool_usage_for(tool_name, limit = 5) # -> ToolMemory
93
+ clear_short_term! / clear_all! / stats # -> delegate
94
+ ```
95
+
96
+ `Agent#initialize` gains optional `memory:` config (embedder/store/persistence) but defaults to the zero-config in-memory, lexical-fallback behavior — so existing code is unchanged.
97
+
98
+ ## Backward compatibility & migration
99
+
100
+ - The `Memory` public API is preserved exactly; `agent.rb` and the runners are untouched functionally.
101
+ - Default construction (`Memory.new` with no args) behaves like today from the caller's perspective — just with better recall when an embedder is configured, and identical lexical recall when not.
102
+ - `relevant_executions` still returns the same formatted-string-or-nil shape consumed at `agent.rb:241`.
103
+
104
+ ## Testing strategy
105
+
106
+ - **Unit**: each memory type with a fake deterministic embedder (as `knowledge_spec.rb` already does) — assert semantic recall ranks the conceptually-closest item first, not the keyword-overlapping one.
107
+ - **Persistence**: `SqliteStore` round-trip — write memories, reopen the DB, recall survives.
108
+ - **Fallback**: with no embedder, recall still returns results via lexical similarity (proves the graceful path).
109
+ - **Facade compat**: the existing `memory_spec.rb` expectations continue to pass (or are updated only where the placeholder behavior was clearly a bug).
110
+ - **Agent integration**: an agent with `reasoning`/knowledge off recalls a semantically-related prior execution injected into its context.
111
+
112
+ ## Dependencies
113
+
114
+ - `sqlite3` gem — added as a runtime dependency, but only required lazily inside `SqliteStore` so the gem loads and the in-memory path works even if it's absent. (If we'd rather avoid the dependency entirely, the fallback is a JSON-file-backed store; SQLite is preferred for query/scale.)
115
+
116
+ ## Rollout
117
+
118
+ Ship in `0.6.0`. `docs/upgrading-to-0.6.md` documents opt-in persistence and embeddings; the default path is unchanged, so it's a no-action upgrade for existing users.
@@ -0,0 +1,191 @@
1
+ # Upgrading to RCrewAI 0.4
2
+
3
+ RCrewAI 0.4 closes the feature-parity gap with the modern CrewAI framework. It
4
+ adds CrewAI's second pillar — **Flows** — alongside **Knowledge (RAG)**,
5
+ structured task output, guardrails, planning, and training/testing.
6
+
7
+ **0.4 is fully backward compatible.** There are no breaking changes: existing
8
+ 0.3 code runs unchanged. Everything below is opt-in.
9
+
10
+ Each new capability has a runnable example under `examples/` — see the links
11
+ throughout.
12
+
13
+ ---
14
+
15
+ ## 1. What you must do
16
+
17
+ Nothing. Upgrade the gem and your existing code keeps working:
18
+
19
+ ```ruby
20
+ gem 'rcrewai', '~> 0.4'
21
+ ```
22
+
23
+ ---
24
+
25
+ ## 2. What you can do (new capabilities)
26
+
27
+ ### 2a. Per-agent LLM
28
+
29
+ Give each agent its own provider/model instead of only the global default.
30
+ Pass a provider symbol, an options hash, or a pre-built client:
31
+
32
+ ```ruby
33
+ worker = RCrewAI::Agent.new(name: 'worker', role: '...', goal: '...',
34
+ llm: { provider: :openai, model: 'gpt-4o-mini' })
35
+ manager = RCrewAI::Agent.new(name: 'manager', role: '...', goal: '...',
36
+ llm: { provider: :anthropic, model: 'claude-3-opus-20240229' })
37
+ ```
38
+
39
+ Omitting `llm:` keeps the global `RCrewAI.configure` behavior. Overrides never
40
+ mutate the global configuration.
41
+
42
+ ### 2b. Structured output, guardrails, and file output
43
+
44
+ Post-process a task's result after the agent produces it:
45
+
46
+ ```ruby
47
+ task = RCrewAI::Task.new(
48
+ name: 'extract', description: '...', agent: agent,
49
+
50
+ # Validate & coerce against a JSON schema. Non-conforming output re-runs the
51
+ # agent with the error fed back. Parsed object on task.structured_output.
52
+ output_schema: { type: 'object', properties: { title: { type: 'string' } },
53
+ required: ['title'] },
54
+
55
+ # Validate & transform. ->(output) { [ok, value_or_error] }. Retries up to
56
+ # guardrail_max_retries (default 3) with the reason fed back to the agent.
57
+ guardrail: ->(out) { [out.length < 5000, 'too long'] },
58
+
59
+ # Persist the result (parent dirs created unless create_directory: false).
60
+ output_file: 'out/report.md', markdown: true
61
+ )
62
+
63
+ task.execute
64
+ task.structured_output # => { "title" => "..." }
65
+ task.raw_result # => the unprocessed string the agent produced
66
+ ```
67
+
68
+ See `examples/structured_output_example.rb`.
69
+
70
+ ### 2c. Knowledge (RAG)
71
+
72
+ Ground agents in your own documents. Sources are chunked, embedded, and stored
73
+ in an in-memory cosine vector store; relevant chunks are injected into each
74
+ task's prompt automatically.
75
+
76
+ ```ruby
77
+ kb = RCrewAI::Knowledge::Base.new(sources: [
78
+ RCrewAI::Knowledge::StringSource.new('Refunds within 30 days.'),
79
+ RCrewAI::Knowledge::FileSource.new('docs/policy.txt'),
80
+ RCrewAI::Knowledge::PdfSource.new('handbook.pdf'),
81
+ RCrewAI::Knowledge::UrlSource.new('https://example.com/faq')
82
+ ])
83
+
84
+ # Agent-level (role-specific):
85
+ agent = RCrewAI::Agent.new(name: 'support', role: '...', goal: '...', knowledge: kb)
86
+
87
+ # Or pass raw sources and let the agent build the base:
88
+ agent = RCrewAI::Agent.new(name: 'support', role: '...', goal: '...',
89
+ knowledge_sources: [RCrewAI::Knowledge::StringSource.new('...')])
90
+
91
+ # Crew-level knowledge is shared with every agent:
92
+ crew = RCrewAI::Crew.new('support', knowledge: kb)
93
+ ```
94
+
95
+ Embeddings default to OpenAI's `text-embedding-3-small`; pass a custom
96
+ `embedder:` (anything responding to `embed(texts)`) to swap the backend.
97
+ See `examples/knowledge_rag_example.rb`.
98
+
99
+ ### 2d. Planning
100
+
101
+ Have a planner pass draft a per-task plan before execution:
102
+
103
+ ```ruby
104
+ crew = RCrewAI::Crew.new('research_crew', planning: true)
105
+ # Optionally use a dedicated (stronger) planner model:
106
+ crew = RCrewAI::Crew.new('research_crew', planning: true,
107
+ planning_llm: { provider: :anthropic, model: 'claude-3-opus-20240229' })
108
+ ```
109
+
110
+ The plan is folded into each task's description. Planning is best-effort: a
111
+ planner error or unparseable output leaves tasks unchanged.
112
+
113
+ ### 2e. Training & testing
114
+
115
+ Iterate on a crew with feedback, or score repeated runs:
116
+
117
+ ```ruby
118
+ # Run N times, collect feedback after each run, persist to JSON.
119
+ crew.train(n_iterations: 3, filename: 'training.json')
120
+
121
+ # Provide feedback programmatically instead of prompting a human:
122
+ crew.train(n_iterations: 3, filename: 'training.json',
123
+ feedback: ->(iteration, result) { "run #{iteration}: #{result[:success_rate]}%" })
124
+
125
+ # Run N times and score each run (defaults to success_rate).
126
+ crew.test(n_iterations: 5)
127
+ # => { iterations: 5, scores: [...], average_score: 92.0 }
128
+ ```
129
+
130
+ See `examples/planning_and_training_example.rb`.
131
+
132
+ ### 2f. Flows
133
+
134
+ Flows are an event-driven workflow engine — the biggest addition in 0.4.
135
+ Subclass `RCrewAI::Flow` and wire methods with a class-level DSL:
136
+
137
+ ```ruby
138
+ class ArticleFlow < RCrewAI::Flow
139
+ start :outline
140
+ def outline
141
+ state.sections = %w[intro body conclusion]
142
+ state.sections.length
143
+ end
144
+
145
+ listen :outline
146
+ def draft(section_count)
147
+ state.words = section_count * 100
148
+ state.words
149
+ end
150
+
151
+ router :draft
152
+ def review(words)
153
+ words >= 250 ? :publish : :expand
154
+ end
155
+
156
+ listen :publish
157
+ def publish = state.status = 'published'
158
+
159
+ listen :expand
160
+ def expand = state.status = 'needs more work'
161
+ end
162
+
163
+ flow = ArticleFlow.new
164
+ flow.kickoff(inputs: { author: 'me' })
165
+ flow.state.status # => "published"
166
+ ```
167
+
168
+ - `start` / `listen` / `router` wire methods into a graph; a listener receives
169
+ its trigger's return value, and a router's return becomes a label listeners
170
+ fire on.
171
+ - Combine triggers with `and_(:a, :b)` (all) and `or_(:a, :b)` (any).
172
+ - **State** is a schemaless object with a UUID, seedable via `kickoff(inputs:)`.
173
+ - **Persistence**: pass `state_store:`
174
+ (`RCrewAI::Flow::FileStateStore.new(dir)` or your own `#save`/`#load`) and
175
+ call `flow.restore(id)` to resume.
176
+ - Invoke a `Crew` inside any step, or pause with `human_feedback('Approve?')`.
177
+
178
+ See `examples/flow_example.rb`.
179
+
180
+ ---
181
+
182
+ ## When to use Flows vs. Crews
183
+
184
+ - **Crew** — a team of agents collaborating on a set of tasks (sequential,
185
+ hierarchical, or async). Reach for a crew when the work is "have these agents
186
+ produce these outputs."
187
+ - **Flow** — explicit, branching orchestration with state. Reach for a flow
188
+ when you need conditional paths, joins, persistence/resumption, or you want to
189
+ coordinate multiple crews and plain Ruby steps.
190
+
191
+ They compose: a Flow step can kick off a Crew.
@@ -0,0 +1,101 @@
1
+ # Upgrading to RCrewAI 0.6
2
+
3
+ RCrewAI 0.6 replaces the placeholder memory with a **cognitive memory** system:
4
+ semantic recall (embeddings + cosine), optional SQLite persistence, and four
5
+ memory types (short-term, long-term, entity, tool).
6
+
7
+ **0.6 is backward compatible.** The `RCrewAI::Memory` public API is unchanged,
8
+ and the default (`Memory.new` with no config) behaves like before from the
9
+ caller's perspective — just with better recall once an embedder is configured.
10
+ Everything below is opt-in.
11
+
12
+ ---
13
+
14
+ ## 1. What you must do
15
+
16
+ Nothing. Upgrade the gem; existing code keeps working:
17
+
18
+ ```ruby
19
+ gem 'rcrewai', '~> 0.6'
20
+ ```
21
+
22
+ Note: `0.6` adds `sqlite3` as a runtime dependency (used only if you opt into
23
+ persistence). It is required lazily, so the in-memory default works even if the
24
+ native extension isn't present.
25
+
26
+ ---
27
+
28
+ ## 2. What you can do (new capabilities)
29
+
30
+ ### 2a. Semantic recall via embeddings
31
+
32
+ By default, memory recall uses lexical (word-overlap) similarity — same as
33
+ before. Pass an embedder to get semantic recall, so an agent remembers
34
+ conceptually related work even when the wording differs:
35
+
36
+ ```ruby
37
+ embedder = RCrewAI::Knowledge::Embedder.new # OpenAI text-embedding-3-small
38
+ agent = RCrewAI::Agent.new(
39
+ name: 'engineer', role: '...', goal: '...',
40
+ memory: { embedder: embedder }
41
+ )
42
+ ```
43
+
44
+ If embedding fails (no API key, network error), recall automatically falls back
45
+ to lexical similarity — memory never breaks agent execution.
46
+
47
+ ### 2b. Persistent memory (SQLite)
48
+
49
+ Give memory a SQLite store and it survives restarts:
50
+
51
+ ```ruby
52
+ store = RCrewAI::Memory::SqliteStore.new(path: '~/.rcrewai/memory.db')
53
+ agent = RCrewAI::Agent.new(
54
+ name: 'engineer', role: '...', goal: '...',
55
+ memory: { embedder: embedder, store: store }
56
+ )
57
+ ```
58
+
59
+ The default store is in-memory (volatile). Any object implementing the store
60
+ interface (`add` / `search` / `all` / `delete` / `delete_record`) can be used —
61
+ e.g. a future Chroma/pgvector adapter.
62
+
63
+ ### 2c. Memory scoping
64
+
65
+ Each agent's memory is scoped to its name by default, so agents sharing a
66
+ persistent store don't read each other's memories. Override with
67
+ `memory: { scope: 'custom' }` if you want deliberate sharing.
68
+
69
+ ### 2d. Memory types (direct access)
70
+
71
+ The `Memory` facade exposes the underlying types for advanced use:
72
+
73
+ ```ruby
74
+ agent.memory.short_term # recent executions, semantic recall, capped
75
+ agent.memory.long_term # durable insights from successful executions, deduped
76
+ agent.memory.entity # facts about entities (people, systems) seen in work
77
+ agent.memory.tool # tool-call history + outcomes
78
+
79
+ agent.memory.entity.entities # => ["Alice", "AWS", ...]
80
+ agent.memory.long_term.recall('...', limit: 3)
81
+ ```
82
+
83
+ ### 2e. Pre-built Memory
84
+
85
+ You can also construct and pass a `Memory` directly:
86
+
87
+ ```ruby
88
+ memory = RCrewAI::Memory.new(scope: 'shared', embedder: embedder, store: store)
89
+ agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...', memory: memory)
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Behavior notes
95
+
96
+ - `add_execution` writes to short-term always, and (on success) promotes a
97
+ deduped insight to long-term and extracts entities.
98
+ - `relevant_executions(task, limit)` recalls across short- and long-term and
99
+ returns the same formatted-string-or-nil shape as before.
100
+ - `clear_short_term!` leaves long-term insights intact; `clear_all!` wipes
101
+ everything.