@crewai-ts/core 0.1.11 → 0.1.12

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/dist/index.cjs CHANGED
@@ -30,10 +30,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
- // node_modules/tsup/assets/cjs_shims.js
33
+ // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.15_tsx@4.22.4_typescript@6.0.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
34
34
  var getImportMetaUrl, importMetaUrl;
35
35
  var init_cjs_shims = __esm({
36
- "node_modules/tsup/assets/cjs_shims.js"() {
36
+ "../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.15_tsx@4.22.4_typescript@6.0.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js"() {
37
37
  "use strict";
38
38
  getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
39
39
  importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
@@ -24,7 +24,7 @@ __export(state_provider_core_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(state_provider_core_exports);
26
26
 
27
- // node_modules/tsup/assets/cjs_shims.js
27
+ // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.15_tsx@4.22.4_typescript@6.0.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
28
28
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
29
29
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
30
30
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@crewai-ts/core",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Unofficial TypeScript port of CrewAI (not affiliated with crewAI, Inc.).",
5
+ "private": false,
5
6
  "keywords": [
6
7
  "crewai",
7
8
  "agents",
@@ -453,15 +454,6 @@
453
454
  "pdf-parse": "^2.4.5",
454
455
  "yaml": "^2.9.0"
455
456
  },
456
- "devDependencies": {
457
- "@eslint/js": "^10.0.1",
458
- "@types/node": "^25.9.1",
459
- "eslint": "^10.4.0",
460
- "tsup": "^8.5.1",
461
- "typescript": "^6.0.3",
462
- "typescript-eslint": "^8.60.0",
463
- "vitest": "^4.1.7"
464
- },
465
457
  "sideEffects": false,
466
458
  "directories": {
467
459
  "doc": "docs",
package/LICENSE DELETED
@@ -1,28 +0,0 @@
1
- MIT License
2
-
3
- This project is an unofficial TypeScript port of CrewAI
4
- (https://github.com/crewAIInc/crewAI), which is distributed under the MIT
5
- License. As required by that license, the original copyright and permission
6
- notice are retained below. This project is not affiliated with, endorsed by,
7
- or maintained by crewAI, Inc.
8
-
9
- Copyright (c) 2025 crewAI, Inc.
10
- Copyright (c) 2026 June
11
-
12
- Permission is hereby granted, free of charge, to any person obtaining a copy
13
- of this software and associated documentation files (the "Software"), to deal
14
- in the Software without restriction, including without limitation the rights
15
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
- copies of the Software, and to permit persons to whom the Software is
17
- furnished to do so, subject to the following conditions:
18
-
19
- The above copyright notice and this permission notice shall be included in all
20
- copies or substantial portions of the Software.
21
-
22
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
- SOFTWARE.
package/README.md DELETED
@@ -1,798 +0,0 @@
1
- # @crewai-ts/core
2
-
3
- [![npm version](https://img.shields.io/npm/v/@crewai-ts/core.svg)](https://www.npmjs.com/package/@crewai-ts/core)
4
- [![license](https://img.shields.io/npm/l/@crewai-ts/core.svg)](./LICENSE)
5
- [![types](https://img.shields.io/npm/types/@crewai-ts/core.svg)](https://www.npmjs.com/package/@crewai-ts/core)
6
-
7
- An **unofficial** TypeScript port of [CrewAI](https://github.com/crewAIInc/crewAI) — build
8
- multi-agent workflows with agents, tasks, crews, and flows using a native TypeScript API.
9
-
10
- The package mirrors CrewAI's runtime semantics (sequential and hierarchical processes,
11
- delegation, planning, memory, knowledge, checkpoints, and streaming) while staying
12
- idiomatic to TypeScript. It ships both **ESM and CommonJS** builds with full type
13
- declarations, and provides Python-style snake_case aliases for common async entry points
14
- to ease migration from the Python library.
15
-
16
- > **Unofficial project.** This is a community port and is **not affiliated with, endorsed
17
- > by, or maintained by crewAI, Inc.** "CrewAI" belongs to its respective owner. The original
18
- > CrewAI is MIT-licensed (Copyright © crewAI, Inc.); this port retains that notice — see
19
- > [License](#license).
20
-
21
- ## Installation
22
-
23
- ```bash
24
- npm install @crewai-ts/core
25
- ```
26
-
27
- ```bash
28
- pnpm add @crewai-ts/core
29
- # or
30
- yarn add @crewai-ts/core
31
- ```
32
-
33
- ## Requirements
34
-
35
- - **Node.js >= 22** (the build targets `node22` and uses `node:sqlite` for the SQLite checkpoint provider)
36
- - Works in both ESM (`import`) and CommonJS (`require`) projects — types are resolved per module system.
37
-
38
- ```ts
39
- // ESM
40
- import { Agent, Crew, Task } from "@crewai-ts/core";
41
- ```
42
-
43
- ```js
44
- // CommonJS
45
- const { Agent, Crew, Task } = require("@crewai-ts/core");
46
- ```
47
-
48
- ## Quick start
49
-
50
- ```ts
51
- import { Agent, Crew, Process, Task, agent, crew, task } from "@crewai-ts/core";
52
-
53
- class ResearchCrew {
54
- @agent
55
- researcher() {
56
- return new Agent({
57
- role: "Researcher",
58
- goal: "Find facts",
59
- backstory: "Careful analyst",
60
- llm: (messages) => `result: ${messages.at(-1)?.content ?? ""}`,
61
- });
62
- }
63
-
64
- @task
65
- researchTask() {
66
- return new Task({
67
- description: "Research {topic}",
68
- expectedOutput: "A concise brief",
69
- agent: this.researcher(),
70
- });
71
- }
72
-
73
- @crew
74
- crew() {
75
- return new Crew({ process: Process.sequential });
76
- }
77
- }
78
-
79
- const result = await new ResearchCrew().crew().kickoff({
80
- inputs: { topic: "CrewAI" },
81
- });
82
-
83
- const batchResults = await new ResearchCrew().crew().kickoffForEach({
84
- inputs: [{ topic: "CrewAI" }, { topic: "TypeScript" }],
85
- });
86
- ```
87
-
88
- > Decorators store only library-private metadata. They do not use `reflect-metadata`,
89
- > parameter decorators, or Nest metadata, so Nest applications should consume this package
90
- > as a normal TypeScript library and keep Nest DI separate.
91
-
92
- CrewAI Python-style snake_case aliases are available for common async entry points,
93
- including `kickoff_async`, `kickoff_for_each`, `kickoff_for_each_async`,
94
- `akickoff_for_each`, `resume_async`, `from_pending`, and `from_state`.
95
-
96
- ## Table of contents
97
-
98
- - [Features](#features)
99
- - [Streaming](#streaming)
100
- - [LiteAgent](#liteagent)
101
- - [Hooks](#hooks)
102
- - [Security](#security)
103
- - [Checkpoints](#checkpoints)
104
- - [Tools](#tools)
105
- - [LLM providers](#llm-providers)
106
- - [Agent planning](#agent-planning)
107
- - [Flows](#flows)
108
- - [Task output files](#task-output-files)
109
- - [Task input files](#task-input-files)
110
- - [Conditional tasks](#conditional-tasks)
111
- - [Human input](#human-input)
112
- - [Crew planning](#crew-planning)
113
- - [Memory](#memory)
114
- - [Knowledge](#knowledge)
115
- - [YAML-backed project config](#yaml-backed-project-config)
116
- - [Development](#development)
117
- - [License](#license)
118
-
119
- ## Features
120
-
121
- **Agents, tasks, and crews**
122
-
123
- - `Agent`, `Task`, `ConditionalTask`, `Crew`, `TaskOutput`, and `CrewOutput`
124
- - `LiteAgent` and `LiteAgentOutput` compatibility layer for direct agent execution
125
- - sequential `Crew.kickoff({ inputs })` and sequential process async task scheduling, including sync barriers and CrewAI-style async validation
126
- - hierarchical process with manager agent / manager LLM validation and coworker delegation tools
127
- - sequential `allowDelegation` agents with coworker delegate / question tools
128
- - `kickoffForEach` / `kickoffForEachAsync` batch execution with aggregate usage metrics
129
- - crew `replay(taskRef, inputs?)` from a task id, name, index, or task object
130
- - crew-level planning that injects per-task execution plans before kickoff
131
- - CrewAI-style default task context aggregation from previous task outputs
132
-
133
- **Decorators and project config**
134
-
135
- - standard TS decorators: `@agent`, `@task`, `@crew`, `@beforeKickoff`, `@afterKickoff`, `@outputJson`, `@outputPydantic`, `@start`, `@listen`, `@router`
136
- - `CrewProject` YAML / object config loading for `agentsConfig` and `tasksConfig`
137
-
138
- **Agent execution controls**
139
-
140
- - iterative agent tool-use loop with `maxIter` and `resultAsAnswer` support
141
- - agent `maxRetryLimit` retries around task execution failures
142
- - agent `maxExecutionTime` timeout enforcement for task execution
143
- - agent and crew `maxRpm` throttling for LLM calls
144
- - agent `useSystemPrompt` control for models that do not accept system-role messages
145
- - agent `systemTemplate`, `promptTemplate`, and `responseTemplate` prompt rendering
146
- - agent `injectDate` / `dateFormat` prompt injection
147
- - callable agent `guardrail` with retry-limit enforcement
148
- - agent-level `PlanningConfig`, `planning`, and legacy `reasoning` compatibility
149
- - deprecated CrewAI agent compatibility fields: `allowCodeExecution`, `codeExecutionMode`, `respectContextWindow`, `multimodal`
150
-
151
- **Tasks**
152
-
153
- - task `outputFile` writing with input interpolation and safe path validation
154
- - task `inputFiles` / `input_files` text file prompt injection, plus an automatic `read_file` tool for named task, crew, and agent input files
155
- - task `outputConverter` / `converter_cls` hooks for structured output conversion
156
- - structured task interpolation for strings, numbers, booleans, arrays, objects, and `null`
157
- - single or ordered multiple task `guardrails` with retry support
158
- - task `humanInput` feedback loops with injectable providers
159
- - task execution counters: `usedTools`, `toolsErrors`, `delegations`, `promptContext`, `processedByAgents`
160
- - task `allowCrewaiTriggerContext` support for `crewai_trigger_payload` kickoff inputs
161
- - `ConditionalTask` skip logic based on the previous task output
162
-
163
- **Tools**
164
-
165
- - `BaseTool` / `StructuredTool` with argument validation, usage limits, tool-call execution, and task-level tool overrides
166
- - tool result caching with `cacheFunction` and shareable `InMemoryToolCache`
167
- - crew `cache: false` control for disabling library tool result caching
168
-
169
- **LLM providers**
170
-
171
- - function or object LLM providers with tool-call options, string model registry, and token usage aggregation
172
-
173
- **Flows**
174
-
175
- - `Flow` with standard TS `@start`, `@listen`, `@router`, `or_`, `and_`, `ask()` input providers, and `@humanFeedback`
176
- - basic `stream: true` crew and flow outputs via `CrewStreamingOutput` / `FlowStreamingOutput`
177
-
178
- **Events and hooks**
179
-
180
- - typed `crewaiEventBus` lifecycle events for crew kickoff, task execution, tool usage, and failures
181
- - agent and crew `stepCallback` hooks for tool / final agent steps
182
- - crew-level `taskCallback` hooks after task callbacks, with duplicate callback suppression
183
- - global before / after LLM and tool call hooks
184
-
185
- **Memory and knowledge**
186
-
187
- - `Memory` / `MemoryScope` with recall / save tools injected into crews when memory is enabled
188
- - `Knowledge` sources (`StringKnowledgeSource`, `TextFileKnowledgeSource`, `JSONKnowledgeSource`, `CSVKnowledgeSource`) with agent and crew context injection
189
-
190
- **State, security, and checkpoints**
191
-
192
- - security `Fingerprint` / `SecurityConfig` on agents, crews, and tasks
193
- - checkpoint `CheckpointConfig`, filesystem `JsonProvider`, and SQLite `SqliteProvider`
194
- - state `EventRecord` / `EventNode` graph for event relationship tracking
195
- - state `RuntimeState` checkpoint serialization, restore, lineage, and fork helpers
196
- - crew `outputLogFile` task execution logs in text or JSON files
197
- - crew `executionLogs` and `taskExecutionOutputJsonFiles` for per-task audit records
198
-
199
- ## Streaming
200
-
201
- Set `stream: true` on a crew or flow to receive a streaming output wrapper from
202
- `kickoff()`. The current TypeScript port exposes the final output as an async
203
- stream chunk and makes the complete result available after iteration.
204
-
205
- ```ts
206
- import { CrewStreamingOutput } from "@crewai-ts/core";
207
-
208
- const streaming = await crew.kickoff() as unknown as CrewStreamingOutput;
209
-
210
- for await (const chunk of streaming) {
211
- console.log(chunk.content);
212
- }
213
-
214
- console.log(streaming.result.raw);
215
- ```
216
-
217
- ## LiteAgent
218
-
219
- `LiteAgent` mirrors CrewAI's deprecated lightweight direct-execution API while
220
- reusing the main `Agent` runtime internally. It returns `LiteAgentOutput`, keeps
221
- the executed messages, exposes usage metrics, and supports the common
222
- snake_case aliases.
223
-
224
- ```ts
225
- import { LiteAgent } from "@crewai-ts/core";
226
-
227
- const agent = new LiteAgent({
228
- role: "Research Assistant",
229
- goal: "Answer quickly",
230
- backstory: "A concise research helper",
231
- llm: (messages) => `answer: ${messages.at(-1)?.content ?? ""}`,
232
- });
233
-
234
- const output = await agent.kickoff_async("What is CrewAI?");
235
- console.log(output.raw);
236
- ```
237
-
238
- ## Hooks
239
-
240
- Register global hooks to inspect, mutate, or block LLM and tool calls. Hook
241
- contexts expose CrewAI-compatible camelCase and snake_case fields where useful.
242
-
243
- ```ts
244
- import { afterLlmCall, beforeToolCall } from "@crewai-ts/core";
245
-
246
- afterLlmCall((context) => {
247
- if (typeof context.response === "string") {
248
- return context.response.replace("SECRET", "[redacted]");
249
- }
250
- return null;
251
- });
252
-
253
- beforeToolCall((context) => {
254
- if (context.tool_name === "delete_file") {
255
- return false;
256
- }
257
- return null;
258
- });
259
- ```
260
-
261
- ## Security
262
-
263
- Agents, crews, and tasks expose a `fingerprint` through `SecurityConfig` for
264
- identity, auditing, and deterministic seed-based identifiers.
265
-
266
- ```ts
267
- import { Agent, Fingerprint, SecurityConfig } from "@crewai-ts/core";
268
-
269
- const securityConfig = new SecurityConfig({
270
- fingerprint: Fingerprint.generate("research-agent", { version: "1.0" }),
271
- });
272
-
273
- const agent = new Agent({
274
- role: "Researcher",
275
- goal: "Find facts",
276
- backstory: "Careful analyst",
277
- securityConfig,
278
- });
279
-
280
- console.log(agent.fingerprint.uuid_str);
281
- ```
282
-
283
- ## Checkpoints
284
-
285
- `CheckpointConfig`, `JsonProvider`, and `SqliteProvider` provide CrewAI-compatible
286
- checkpoint configuration and checkpoint storage. Agents, crews, and flows accept
287
- a `checkpoint` option.
288
-
289
- ```ts
290
- import { CheckpointConfig, JsonProvider, SqliteProvider } from "@crewai-ts/core";
291
-
292
- const checkpoint = new CheckpointConfig({
293
- location: ".checkpoints",
294
- onEvents: ["task_completed"],
295
- provider: new JsonProvider(),
296
- });
297
-
298
- const sqliteCheckpoint = new CheckpointConfig({
299
- location: ".checkpoints.db",
300
- provider: new SqliteProvider(),
301
- });
302
- ```
303
-
304
- ## Tools
305
-
306
- Tools can be attached to agents or tasks. Task tools take precedence during that
307
- task, matching CrewAI's task-level override behavior.
308
-
309
- ```ts
310
- import { Agent, StructuredTool, Task } from "@crewai-ts/core";
311
-
312
- const search = new StructuredTool({
313
- name: "search",
314
- description: "Search for a topic",
315
- argsSchema: {
316
- query: { type: "string", required: true },
317
- },
318
- maxUsageCount: 3,
319
- func: ({ query }) => `found ${String(query)}`,
320
- });
321
-
322
- const researcher = new Agent({
323
- role: "Researcher",
324
- goal: "Find facts",
325
- backstory: "Careful analyst",
326
- tools: [search],
327
- maxRpm: 30,
328
- stepCallback: (step) => {
329
- console.log(step.type, step.output);
330
- },
331
- llm: () => ({ toolName: "search", arguments: { query: "CrewAI" } }),
332
- });
333
-
334
- const task = new Task({
335
- description: "Research {topic}",
336
- expectedOutput: "A concise brief",
337
- agent: researcher,
338
- guardrails: [
339
- (output) => [output.raw.length > 0, output.raw],
340
- ],
341
- });
342
- ```
343
-
344
- When an LLM returns a tool call, the agent executes the tool, appends the tool
345
- result to the message list, and calls the LLM again until it returns a final
346
- answer or reaches `maxIter`. Tools marked `resultAsAnswer` return their tool
347
- output directly. Set `functionCallingLlm` on an `Agent` or `Crew` when tool-call
348
- selection should use a separate model from the main answer-generating LLM.
349
-
350
- Tools cache successful outputs by normalized arguments. Use `cacheFunction` to
351
- skip selected writes, or pass a shared `InMemoryToolCache` to reuse cached
352
- results across tool instances.
353
-
354
- ## LLM providers
355
-
356
- Agents accept either a function LLM, an object provider with `call()`, or a
357
- registered model name. Function LLMs receive the message list and call options;
358
- object providers can expose `getUsageMetrics()` or CrewAI-style
359
- `getTokenUsageSummary()` for exact token accounting. When they do not, the
360
- runtime records an estimated usage count.
361
-
362
- ```ts
363
- import { Agent, registerLLMProvider } from "@crewai-ts/core";
364
-
365
- registerLLMProvider("local/research", {
366
- call: async (messages, { tools } = {}) => {
367
- return `tools available: ${tools?.map((tool) => tool.name).join(", ") ?? "none"}`;
368
- },
369
- getUsageMetrics: () => ({
370
- totalTokens: 12,
371
- promptTokens: 8,
372
- cachedPromptTokens: 0,
373
- completionTokens: 4,
374
- reasoningTokens: 0,
375
- cacheCreationTokens: 0,
376
- successfulRequests: 1,
377
- }),
378
- });
379
-
380
- const researcher = new Agent({
381
- role: "Researcher",
382
- goal: "Find facts",
383
- backstory: "Careful analyst",
384
- llm: "local/research",
385
- });
386
-
387
- await researcher.kickoff("Summarize the notes", {
388
- inputFiles: {
389
- notes: "docs/notes.txt",
390
- },
391
- });
392
-
393
- await researcher.kickoff([
394
- {
395
- role: "user",
396
- content: "Summarize the uploaded notes",
397
- files: {
398
- notes: "docs/notes.txt",
399
- },
400
- },
401
- ]);
402
- ```
403
-
404
- ## Agent planning
405
-
406
- Agents can create a reasoning plan before executing a task. `planning: true`
407
- uses a bounded low-effort default config, while `PlanningConfig` exposes the
408
- custom prompt and limit knobs.
409
-
410
- ```ts
411
- import { Agent, PlanningConfig } from "@crewai-ts/core";
412
-
413
- const researcher = new Agent({
414
- role: "Researcher",
415
- goal: "Find facts",
416
- backstory: "Careful analyst",
417
- llm: "local/research",
418
- planningConfig: new PlanningConfig({
419
- maxSteps: 10,
420
- planPrompt: "Plan this task: {description}",
421
- }),
422
- });
423
-
424
- const answer = await researcher.kickoff("Research CrewAI");
425
- ```
426
-
427
- ## Flows
428
-
429
- Flows run decorated methods as a stateful workflow. `@start` methods begin the
430
- run, `@listen` methods react to completed methods or router path strings, and
431
- `@router` methods return the next path label.
432
-
433
- ```ts
434
- import { Flow, and_, listen, router, start } from "@crewai-ts/core";
435
-
436
- class ResearchFlow extends Flow<{ topic?: string; done?: boolean }> {
437
- @start()
438
- begin(inputs: { topic: string }) {
439
- this.state.topic = inputs.topic;
440
- return inputs.topic;
441
- }
442
-
443
- @router("begin")
444
- route() {
445
- return this.state.topic ? "research" : "skip";
446
- }
447
-
448
- @listen(and_("research", "begin"))
449
- finish() {
450
- this.state.done = true;
451
- return `researched ${this.state.topic}`;
452
- }
453
- }
454
-
455
- const result = await new ResearchFlow().kickoff({
456
- inputs: { topic: "CrewAI" },
457
- });
458
- ```
459
-
460
- `@start("path")` is also supported for conditional starts after a method or
461
- router path fires. Flow execution is bounded by `maxMethodCalls` so cyclic
462
- flows fail clearly instead of running forever.
463
-
464
- Inside a flow, use `this.kickoffCrew(crew)` to run a crew with the flow's
465
- `inputFiles` / `input_files` automatically forwarded.
466
-
467
- Flows can request user input through `this.ask()`. Set an `inputProvider` on
468
- the flow instance or `flowConfig.inputProvider` globally. Providers may return
469
- a string, `null`, or `{ text, metadata }`; responses are available through
470
- `flow.inputHistory`.
471
-
472
- ```ts
473
- const flow = new ResearchFlow({
474
- inputProvider: {
475
- requestInput: async (_message, _flow, metadata) => ({
476
- text: "CrewAI",
477
- metadata: { source: metadata?.channel },
478
- }),
479
- },
480
- });
481
-
482
- const topic = await flow.ask("Topic?", {
483
- metadata: { channel: "research" },
484
- timeout: 30,
485
- });
486
- ```
487
-
488
- Flow methods can also be wrapped with `@humanFeedback`. The method output is
489
- sent to a feedback provider, the result is stored on
490
- `flow.lastHumanFeedback` / `flow.humanFeedbackHistory`, and `emit` values make
491
- the method act as a router.
492
-
493
- ```ts
494
- class ReviewFlow extends Flow {
495
- @start()
496
- @humanFeedback({
497
- message: "Review this draft",
498
- emit: ["approved", "rejected"],
499
- provider: {
500
- requestFeedback: async () => "approved",
501
- },
502
- })
503
- draft() {
504
- return "Draft content";
505
- }
506
-
507
- @listen("approved")
508
- publish() {
509
- return this.lastHumanFeedback?.output;
510
- }
511
- }
512
- ```
513
-
514
- Providers that hand off review to an external system can throw
515
- `HumanFeedbackPending`. `kickoff()` returns that object, emits
516
- `method_execution_paused` and `flow_paused`, and does not treat the pause as a
517
- Flow failure. The same Flow instance can continue with `resume(feedback)` or
518
- `resumeAsync(feedback)`, which records `lastHumanFeedback` and resumes any
519
- listeners waiting on the paused method or emitted outcome.
520
-
521
- ```ts
522
- provider: {
523
- requestFeedback: (context) => {
524
- throw new HumanFeedbackPending({
525
- context,
526
- callbackInfo: { ticketId: "review-123" },
527
- });
528
- },
529
- }
530
- ```
531
-
532
- To resume after process restart, provide a `JsonFlowPersistence` in the Flow
533
- constructor. Pending feedback is written with the current state and can be
534
- restored with `Flow.fromPending(flowId, persistence)`.
535
-
536
- ```ts
537
- const persistence = new JsonFlowPersistence(".flows");
538
- const pending = await flow.kickoff();
539
-
540
- if (pending instanceof HumanFeedbackPending && pending.context.flowId) {
541
- const restored = await ReviewFlow.fromPending(pending.context.flowId, persistence);
542
- await restored.resume("approved");
543
- }
544
- ```
545
-
546
- The same persistence object stores ordinary Flow state after each completed
547
- method. Use `Flow.fromState(flowId, persistence)` to restore the latest state
548
- snapshot for a Flow id.
549
-
550
- After a run, `flow.methodOutputs`, `flow.completedMethods`,
551
- `flow.methodExecutionCounts`, and `flow.executionTrace` expose the last
552
- execution's method-level runtime state.
553
-
554
- Use `getFlowStructure(flowOrClass)` to inspect the static Flow graph for
555
- visualization or tooling.
556
-
557
- Use `flow.toExecutionData()` and `flow.reload(data)` to export and restore the
558
- last run's state, completed methods, method outputs, and execution trace.
559
- Flows emit `flow_started`, `flow_input_requested`, `flow_input_received`,
560
- `human_feedback_requested`, `human_feedback_received`,
561
- `method_execution_started`, `method_execution_finished`,
562
- `method_execution_failed`, `method_execution_paused`, `flow_finished`,
563
- `flow_failed`, and `flow_paused` events on `crewaiEventBus`.
564
-
565
- ## Task output files
566
-
567
- Tasks can persist their final output to a file. Paths support the same input
568
- interpolation as task descriptions, and directories are created by default.
569
-
570
- ```ts
571
- const report = new Task({
572
- description: "Research {topic}",
573
- expectedOutput: "A concise brief",
574
- agent: researcher,
575
- outputFile: "reports/{topic}.md",
576
- });
577
- ```
578
-
579
- ## Task input files
580
-
581
- Tasks can attach named text input files. The runtime loads their content into
582
- the task prompt so function LLMs and text-only providers can consume the same
583
- named file surface. When input files are present, the runtime also exposes a
584
- `read_file` tool that accepts `{ file_name: "notes" }`.
585
-
586
- ```ts
587
- const task = new Task({
588
- description: "Summarize the provided notes",
589
- expectedOutput: "A concise summary",
590
- agent: researcher,
591
- inputFiles: {
592
- notes: "docs/notes.txt",
593
- inline: {
594
- filename: "brief.md",
595
- contentType: "text/markdown",
596
- content: "# Brief\nSummarize this.",
597
- },
598
- },
599
- });
600
-
601
- const result = await new Crew({ agents: [researcher], tasks: [task] }).kickoff({
602
- inputFiles: {
603
- sharedNotes: "docs/shared-notes.txt",
604
- },
605
- });
606
- ```
607
-
608
- Structured file objects passed through `kickoff({ inputs })` are extracted into
609
- the same input-file surface and removed from interpolation inputs. Raw string
610
- inputs are left untouched, so normal values such as `"docs/notes.txt"` are not
611
- treated as files unless passed through `inputFiles` / `input_files`.
612
-
613
- ## Conditional tasks
614
-
615
- `ConditionalTask` evaluates the previous task output before running. When its
616
- condition returns false, the crew records an empty raw task output and continues.
617
-
618
- ```ts
619
- import { ConditionalTask } from "@crewai-ts/core";
620
-
621
- const followUp = new ConditionalTask({
622
- description: "Write follow-up details",
623
- expectedOutput: "Only needed when the previous task asks for more detail",
624
- agent: researcher,
625
- condition: (output) => output.raw.includes("needs follow-up"),
626
- });
627
- ```
628
-
629
- ## Human input
630
-
631
- Set `humanInput` on a task to request feedback after the first output. Empty
632
- feedback accepts the output; non-empty feedback is appended to the next prompt
633
- and the task reruns. Server apps should inject their own provider instead of
634
- using terminal input.
635
-
636
- ```ts
637
- const crew = new Crew({
638
- agents: [reviewer],
639
- tasks: [
640
- new Task({
641
- description: "Review the report",
642
- expectedOutput: "Approved report",
643
- agent: reviewer,
644
- humanInput: true,
645
- }),
646
- ],
647
- humanInputProvider: {
648
- requestFeedback: async ({ output }) => {
649
- return output.raw.includes("approved") ? "" : "Please include approval.";
650
- },
651
- },
652
- });
653
- ```
654
-
655
- ## Crew planning
656
-
657
- Enable `planning` to run a planner LLM before task execution. The planner returns
658
- one plan per task, and each task prompt receives its current plan without
659
- mutating the original task description.
660
-
661
- ```ts
662
- const crew = new Crew({
663
- agents: [researcher],
664
- tasks: [report],
665
- planning: true,
666
- planningLlm: "gpt-4o-mini",
667
- });
668
- ```
669
-
670
- ## Memory
671
-
672
- Enable memory on a crew to append relevant memory context to task prompts and
673
- inject recall/save tools into task execution. Agent-level memory is also
674
- available through `new Agent({ memory })` and stores completed agent results.
675
-
676
- ```ts
677
- import { Agent, Crew, Memory, Process, Task } from "@crewai-ts/core";
678
-
679
- const memory = new Memory();
680
- memory.remember("CrewAI supports sequential crews");
681
-
682
- const researcher = new Agent({
683
- role: "Researcher",
684
- goal: "Use memory",
685
- backstory: "Careful analyst",
686
- llm: () => ({
687
- toolName: "Search_memory",
688
- arguments: { queries: ["sequential crews"] },
689
- }),
690
- });
691
-
692
- const crew = new Crew({
693
- agents: [researcher],
694
- tasks: [
695
- new Task({
696
- description: "Recall CrewAI facts",
697
- expectedOutput: "Relevant memories",
698
- agent: researcher,
699
- }),
700
- ],
701
- process: Process.sequential,
702
- memory,
703
- });
704
- ```
705
-
706
- ## Knowledge
707
-
708
- Attach `Knowledge` or `knowledgeSources` to an agent or crew to inject relevant
709
- source snippets into task prompts as additional information.
710
-
711
- ```ts
712
- import { Agent, Crew, StringKnowledgeSource, TextFileKnowledgeSource, Task } from "@crewai-ts/core";
713
-
714
- const researcher = new Agent({
715
- role: "Researcher",
716
- goal: "Use knowledge",
717
- backstory: "Careful analyst",
718
- llm: (messages) => messages.at(-1)?.content ?? "",
719
- });
720
-
721
- const crew = new Crew({
722
- agents: [researcher],
723
- tasks: [
724
- new Task({
725
- description: "Explain Nest integration",
726
- expectedOutput: "Integration guidance",
727
- agent: researcher,
728
- }),
729
- ],
730
- knowledgeSources: [
731
- new StringKnowledgeSource("Nest should consume crewai-ts as a normal TypeScript library."),
732
- new TextFileKnowledgeSource("knowledge/nest-notes.txt"),
733
- ],
734
- });
735
-
736
- crew.resetMemories("knowledge");
737
- ```
738
-
739
- ## YAML-backed project config
740
-
741
- `CrewProject` mirrors CrewAI's `agents.yaml` / `tasks.yaml` workflow. String
742
- references in config are resolved only against this library's decorated methods.
743
-
744
- ```ts
745
- import {
746
- Agent,
747
- Crew,
748
- CrewProject,
749
- Process,
750
- Task,
751
- agent,
752
- agentOptionsFromConfig,
753
- crew,
754
- task,
755
- taskOptionsFromConfig,
756
- } from "@crewai-ts/core";
757
-
758
- class ResearchCrew extends CrewProject {
759
- agentsConfig = "config/agents.yaml";
760
- tasksConfig = "config/tasks.yaml";
761
-
762
- @agent
763
- researcher() {
764
- return new Agent(agentOptionsFromConfig(this.agentConfig("researcher")));
765
- }
766
-
767
- @task
768
- researchTask() {
769
- return new Task(taskOptionsFromConfig(this.taskConfig("researchTask")));
770
- }
771
-
772
- @crew
773
- crew() {
774
- return new Crew({ process: Process.sequential });
775
- }
776
- }
777
- ```
778
-
779
- ## Development
780
-
781
- This repo is built with [tsup](https://tsup.egoist.dev/) (ESM + CJS + type declarations)
782
- and tested with [Vitest](https://vitest.dev/).
783
-
784
- ```bash
785
- npm run build # build ESM + CJS output and declarations
786
- npm run check # type-check in no-emit mode
787
- npm test # run the Vitest suite
788
- npm run lint # run ESLint
789
- ```
790
-
791
- ## License
792
-
793
- [MIT](./LICENSE) © June
794
-
795
- This project is an unofficial TypeScript port of [CrewAI](https://github.com/crewAIInc/crewAI)
796
- (Copyright © crewAI, Inc.), which is distributed under the MIT License. It is not affiliated
797
- with or endorsed by crewAI, Inc. As required by the MIT License, the original copyright and
798
- permission notice are retained in [LICENSE](./LICENSE).