@crewai-ts/core 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -708
- package/dist/index.cjs +2 -2
- package/dist/state-provider-core.cjs +1 -1
- package/package.json +2 -10
- package/LICENSE +0 -28
package/README.md
CHANGED
|
@@ -1,51 +1,56 @@
|
|
|
1
1
|
# @crewai-ts/core
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@crewai-ts/core)
|
|
4
|
-
[](./LICENSE)
|
|
5
4
|
[](https://www.npmjs.com/package/@crewai-ts/core)
|
|
6
5
|
|
|
7
|
-
An **unofficial** TypeScript port of [CrewAI](https://github.com/crewAIInc/crewAI)
|
|
8
|
-
multi-agent workflows with agents, tasks, crews, and flows using a native TypeScript API.
|
|
6
|
+
An **unofficial** TypeScript port of [CrewAI](https://github.com/crewAIInc/crewAI) for building multi-agent workflows with agents, tasks, crews, flows, memory, knowledge, tools, checkpoints, and streaming.
|
|
9
7
|
|
|
10
|
-
|
|
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.
|
|
8
|
+
This project is not affiliated with, endorsed by, or maintained by crewAI, Inc.
|
|
15
9
|
|
|
16
|
-
|
|
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).
|
|
10
|
+
## Install
|
|
20
11
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```bash
|
|
12
|
+
```sh
|
|
24
13
|
npm install @crewai-ts/core
|
|
25
14
|
```
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
pnpm add @crewai-ts/core
|
|
29
|
-
# or
|
|
30
|
-
yarn add @crewai-ts/core
|
|
31
|
-
```
|
|
16
|
+
Requirements:
|
|
32
17
|
|
|
33
|
-
|
|
18
|
+
- Node.js 22 or later
|
|
19
|
+
- ESM and CommonJS projects are both supported
|
|
20
|
+
- Type declarations are included
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
- Works in both ESM (`import`) and CommonJS (`require`) projects — types are resolved per module system.
|
|
22
|
+
## Quick Start
|
|
37
23
|
|
|
38
24
|
```ts
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
import { Agent, Crew, Process, Task } from "@crewai-ts/core";
|
|
26
|
+
|
|
27
|
+
const researcher = new Agent({
|
|
28
|
+
role: "Researcher",
|
|
29
|
+
goal: "Find useful implementation details",
|
|
30
|
+
backstory: "A careful technical analyst.",
|
|
31
|
+
llm: (messages) => `researched: ${messages.at(-1)?.content ?? ""}`,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const task = new Task({
|
|
35
|
+
description: "Research {topic}",
|
|
36
|
+
expectedOutput: "A concise implementation brief",
|
|
37
|
+
agent: researcher,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const crew = new Crew({
|
|
41
|
+
agents: [researcher],
|
|
42
|
+
tasks: [task],
|
|
43
|
+
process: Process.sequential,
|
|
44
|
+
});
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
const result = await crew.kickoff({
|
|
47
|
+
inputs: { topic: "CrewAI with TypeScript" },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
console.log(result.raw);
|
|
46
51
|
```
|
|
47
52
|
|
|
48
|
-
##
|
|
53
|
+
## Decorator Style
|
|
49
54
|
|
|
50
55
|
```ts
|
|
51
56
|
import { Agent, Crew, Process, Task, agent, crew, task } from "@crewai-ts/core";
|
|
@@ -72,727 +77,98 @@ class ResearchCrew {
|
|
|
72
77
|
|
|
73
78
|
@crew
|
|
74
79
|
crew() {
|
|
75
|
-
return new Crew({
|
|
80
|
+
return new Crew({
|
|
81
|
+
agents: [this.researcher()],
|
|
82
|
+
tasks: [this.researchTask()],
|
|
83
|
+
process: Process.sequential,
|
|
84
|
+
});
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
const result = await new ResearchCrew().crew().kickoff({
|
|
80
89
|
inputs: { topic: "CrewAI" },
|
|
81
90
|
});
|
|
82
|
-
|
|
83
|
-
const batchResults = await new ResearchCrew().crew().kickoffForEach({
|
|
84
|
-
inputs: [{ topic: "CrewAI" }, { topic: "TypeScript" }],
|
|
85
|
-
});
|
|
86
91
|
```
|
|
87
92
|
|
|
88
|
-
|
|
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**
|
|
93
|
+
## LLM Providers
|
|
164
94
|
|
|
165
|
-
|
|
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.
|
|
95
|
+
Pass a function LLM directly:
|
|
204
96
|
|
|
205
97
|
```ts
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
});
|
|
98
|
+
const llm = (messages: Array<{ content?: string }>) => {
|
|
99
|
+
return `answer: ${messages.at(-1)?.content ?? ""}`;
|
|
100
|
+
};
|
|
259
101
|
```
|
|
260
102
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
Agents, crews, and tasks expose a `fingerprint` through `SecurityConfig` for
|
|
264
|
-
identity, auditing, and deterministic seed-based identifiers.
|
|
103
|
+
Or register a named provider:
|
|
265
104
|
|
|
266
105
|
```ts
|
|
267
|
-
import { Agent,
|
|
106
|
+
import { Agent, registerLLMProvider } from "@crewai-ts/core";
|
|
268
107
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
});
|
|
108
|
+
registerLLMProvider("demo/provider", () => ({
|
|
109
|
+
call: async (messages) => `provider result: ${messages.at(-1)?.content ?? ""}`,
|
|
110
|
+
}));
|
|
272
111
|
|
|
273
112
|
const agent = new Agent({
|
|
274
|
-
role: "
|
|
275
|
-
goal: "
|
|
276
|
-
backstory: "
|
|
277
|
-
|
|
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(),
|
|
113
|
+
role: "Assistant",
|
|
114
|
+
goal: "Use a registered provider",
|
|
115
|
+
backstory: "A deterministic assistant.",
|
|
116
|
+
llm: "demo/provider",
|
|
301
117
|
});
|
|
302
118
|
```
|
|
303
119
|
|
|
304
120
|
## Tools
|
|
305
121
|
|
|
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
122
|
```ts
|
|
310
123
|
import { Agent, StructuredTool, Task } from "@crewai-ts/core";
|
|
311
124
|
|
|
312
125
|
const search = new StructuredTool({
|
|
313
126
|
name: "search",
|
|
314
|
-
description: "Search
|
|
315
|
-
|
|
316
|
-
|
|
127
|
+
description: "Search internal notes",
|
|
128
|
+
schema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {
|
|
131
|
+
query: { type: "string" },
|
|
132
|
+
},
|
|
133
|
+
required: ["query"],
|
|
317
134
|
},
|
|
318
|
-
|
|
319
|
-
func: ({ query }) => `found ${String(query)}`,
|
|
135
|
+
func: async ({ query }) => `result for ${query}`,
|
|
320
136
|
});
|
|
321
137
|
|
|
322
138
|
const researcher = new Agent({
|
|
323
139
|
role: "Researcher",
|
|
324
|
-
goal: "
|
|
325
|
-
backstory: "
|
|
140
|
+
goal: "Use tools when useful",
|
|
141
|
+
backstory: "Tool-using analyst.",
|
|
326
142
|
tools: [search],
|
|
327
|
-
maxRpm: 30,
|
|
328
|
-
stepCallback: (step) => {
|
|
329
|
-
console.log(step.type, step.output);
|
|
330
|
-
},
|
|
331
143
|
llm: () => ({ toolName: "search", arguments: { query: "CrewAI" } }),
|
|
332
144
|
});
|
|
333
145
|
|
|
334
146
|
const task = new Task({
|
|
335
|
-
description: "
|
|
336
|
-
expectedOutput: "
|
|
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",
|
|
147
|
+
description: "Search for CrewAI information",
|
|
148
|
+
expectedOutput: "Search result",
|
|
590
149
|
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
150
|
});
|
|
704
151
|
```
|
|
705
152
|
|
|
706
|
-
##
|
|
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/).
|
|
153
|
+
## Features
|
|
783
154
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
155
|
+
- `Agent`, `Task`, `ConditionalTask`, `Crew`, `TaskOutput`, and `CrewOutput`
|
|
156
|
+
- Sequential and hierarchical process support
|
|
157
|
+
- Crew kickoff, batch kickoff, replay, planning, and usage metrics
|
|
158
|
+
- Standard TypeScript decorators: `@agent`, `@task`, `@crew`, `@beforeKickoff`, `@afterKickoff`
|
|
159
|
+
- Tool calling with `BaseTool` and `StructuredTool`
|
|
160
|
+
- Memory and knowledge sources
|
|
161
|
+
- JSON and SQLite checkpoint providers
|
|
162
|
+
- Flow APIs with `@start`, `@listen`, `@router`, `and_`, and `or_`
|
|
163
|
+
- Human input providers and task guardrails
|
|
164
|
+
- Streaming crew and flow output helpers
|
|
165
|
+
- Python-style snake_case compatibility aliases for common CrewAI entry points
|
|
166
|
+
|
|
167
|
+
## Related Packages
|
|
168
|
+
|
|
169
|
+
- `@crewai-ts/nestjs`: NestJS dependency-injection integration
|
|
170
|
+
- `@crewai-ts/cli`: CLI helpers for CrewAI-style TypeScript projects
|
|
790
171
|
|
|
791
172
|
## License
|
|
792
173
|
|
|
793
|
-
|
|
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).
|
|
174
|
+
MIT
|
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.
|
|
3
|
+
"version": "0.1.13",
|
|
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.
|