@strav/brain 0.4.31 → 1.0.0-alpha.9
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/package.json +17 -20
- package/src/agent.ts +42 -76
- package/src/agent_result.ts +32 -0
- package/src/agent_runner.ts +61 -0
- package/src/brain_config.ts +72 -0
- package/src/brain_error.ts +29 -0
- package/src/brain_manager.ts +170 -123
- package/src/brain_provider.ts +90 -6
- package/src/define_tool.ts +42 -0
- package/src/index.ts +40 -42
- package/src/provider.ts +74 -0
- package/src/providers/anthropic_provider.ts +347 -231
- package/src/thread.ts +99 -0
- package/src/tool.ts +28 -44
- package/src/tool_execution_error.ts +26 -0
- package/src/types.ts +129 -241
- package/CHANGELOG.md +0 -44
- package/README.md +0 -121
- package/src/helpers.ts +0 -1082
- package/src/mcp_toolbox.ts +0 -62
- package/src/memory/context_budget.ts +0 -120
- package/src/memory/index.ts +0 -17
- package/src/memory/memory_manager.ts +0 -168
- package/src/memory/semantic_memory.ts +0 -89
- package/src/memory/strategies/sliding_window.ts +0 -20
- package/src/memory/strategies/summarize.ts +0 -157
- package/src/memory/thread_store.ts +0 -56
- package/src/memory/token_counter.ts +0 -101
- package/src/memory/types.ts +0 -68
- package/src/providers/google_provider.ts +0 -496
- package/src/providers/openai_provider.ts +0 -569
- package/src/providers/openai_responses_provider.ts +0 -321
- package/src/utils/error_scrub.ts +0 -5
- package/src/utils/prompt.ts +0 -65
- package/src/utils/retry.ts +0 -104
- package/src/utils/schema.ts +0 -27
- package/src/utils/sse_parser.ts +0 -62
- package/src/workflow.ts +0 -199
- package/tsconfig.json +0 -5
package/src/workflow.ts
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { Workflow as BaseWorkflow } from '@strav/workflow'
|
|
2
|
-
import type { WorkflowContext as BaseContext } from '@strav/workflow'
|
|
3
|
-
import { AgentRunner } from './helpers.ts'
|
|
4
|
-
import type { Agent } from './agent.ts'
|
|
5
|
-
import type { AgentResult, SuspendedRun, WorkflowResult, Usage } from './types.ts'
|
|
6
|
-
|
|
7
|
-
// ── AI Workflow Context ─────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
export interface WorkflowContext {
|
|
10
|
-
input: Record<string, unknown>
|
|
11
|
-
results: Record<string, AgentResult>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type StepMapInput = (ctx: WorkflowContext) => Record<string, unknown> | string
|
|
15
|
-
|
|
16
|
-
// ── Utilities ───────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
function resolveInput(mapInput: StepMapInput | undefined, ctx: BaseContext): string {
|
|
19
|
-
if (!mapInput) return JSON.stringify(ctx.input)
|
|
20
|
-
const mapped = mapInput(ctx as unknown as WorkflowContext)
|
|
21
|
-
return typeof mapped === 'string' ? mapped : JSON.stringify(mapped)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function addUsage(total: Usage, add: Usage): void {
|
|
25
|
-
total.inputTokens += add.inputTokens
|
|
26
|
-
total.outputTokens += add.outputTokens
|
|
27
|
-
total.totalTokens += add.totalTokens
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Workflow orchestration runs agents to completion; suspension is a standalone
|
|
31
|
-
// primitive on AgentRunner. Surface a clear error rather than silently swallowing.
|
|
32
|
-
function assertCompleted(
|
|
33
|
-
result: AgentResult | SuspendedRun,
|
|
34
|
-
stepName: string
|
|
35
|
-
): asserts result is AgentResult {
|
|
36
|
-
if ((result as SuspendedRun).status === 'suspended') {
|
|
37
|
-
throw new Error(
|
|
38
|
-
`Workflow step "${stepName}" suspended — Workflow does not support agent suspension. ` +
|
|
39
|
-
`Use AgentRunner.run()/resume() directly, or ensure workflow agents don't define shouldSuspend.`
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// ── Workflow Builder ────────────────────────────────────────────────────────
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Multi-agent workflow orchestrator built on `@strav/workflow`.
|
|
48
|
-
*
|
|
49
|
-
* Supports sequential steps, parallel fan-out, routing, and loops.
|
|
50
|
-
* Each step wraps an Agent execution through the general-purpose workflow engine.
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* const result = await brain.workflow('content-pipeline')
|
|
54
|
-
* .step('research', ResearchAgent)
|
|
55
|
-
* .step('write', WriterAgent, (ctx) => ({
|
|
56
|
-
* topic: ctx.results.research.data.summary,
|
|
57
|
-
* }))
|
|
58
|
-
* .step('review', ReviewerAgent)
|
|
59
|
-
* .run({ topic: 'AI in healthcare' })
|
|
60
|
-
*/
|
|
61
|
-
export class Workflow {
|
|
62
|
-
private pipeline: BaseWorkflow
|
|
63
|
-
private totalUsage: Usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
|
64
|
-
|
|
65
|
-
constructor(name: string) {
|
|
66
|
-
this.pipeline = new BaseWorkflow(name)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Add a sequential step. Runs after all previous steps complete.
|
|
71
|
-
* Use `mapInput` to transform context into the agent's input.
|
|
72
|
-
*/
|
|
73
|
-
step(name: string, agent: new () => Agent, mapInput?: StepMapInput): this {
|
|
74
|
-
this.pipeline.step(name, async (ctx: BaseContext) => {
|
|
75
|
-
const inputText = resolveInput(mapInput, ctx)
|
|
76
|
-
const result = await new AgentRunner(agent).input(inputText).run()
|
|
77
|
-
assertCompleted(result, name)
|
|
78
|
-
addUsage(this.totalUsage, result.usage)
|
|
79
|
-
return result
|
|
80
|
-
})
|
|
81
|
-
return this
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Run multiple agents in parallel. All agents receive the same context.
|
|
86
|
-
* Each agent's result is stored under its name in the workflow results.
|
|
87
|
-
*/
|
|
88
|
-
parallel(
|
|
89
|
-
name: string,
|
|
90
|
-
agents: { name: string; agent: new () => Agent; mapInput?: StepMapInput }[]
|
|
91
|
-
): this {
|
|
92
|
-
this.pipeline.parallel(
|
|
93
|
-
name,
|
|
94
|
-
agents.map(a => ({
|
|
95
|
-
name: a.name,
|
|
96
|
-
handler: async (ctx: BaseContext) => {
|
|
97
|
-
const inputText = resolveInput(a.mapInput, ctx)
|
|
98
|
-
const result = await new AgentRunner(a.agent).input(inputText).run()
|
|
99
|
-
assertCompleted(result, `${name}.${a.name}`)
|
|
100
|
-
addUsage(this.totalUsage, result.usage)
|
|
101
|
-
return result
|
|
102
|
-
},
|
|
103
|
-
}))
|
|
104
|
-
)
|
|
105
|
-
return this
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Route to a specialized agent based on a router agent's output.
|
|
110
|
-
* The router agent should return structured output with a `route` field
|
|
111
|
-
* that matches one of the branch keys.
|
|
112
|
-
*/
|
|
113
|
-
route(
|
|
114
|
-
name: string,
|
|
115
|
-
router: new () => Agent,
|
|
116
|
-
branches: Record<string, new () => Agent>,
|
|
117
|
-
mapInput?: StepMapInput
|
|
118
|
-
): this {
|
|
119
|
-
// Router step: run the router agent, store as `${name}:router`
|
|
120
|
-
this.pipeline.step(`${name}:router`, async (ctx: BaseContext) => {
|
|
121
|
-
const inputText = resolveInput(mapInput, ctx)
|
|
122
|
-
const result = await new AgentRunner(router).input(inputText).run()
|
|
123
|
-
assertCompleted(result, `${name}:router`)
|
|
124
|
-
addUsage(this.totalUsage, result.usage)
|
|
125
|
-
return result
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// Branch step: dispatch to the matching branch agent
|
|
129
|
-
this.pipeline.route(
|
|
130
|
-
name,
|
|
131
|
-
(ctx: BaseContext) => {
|
|
132
|
-
const routerResult = ctx.results[`${name}:router`] as AgentResult
|
|
133
|
-
return routerResult.data?.route ?? routerResult.text?.trim() ?? ''
|
|
134
|
-
},
|
|
135
|
-
Object.fromEntries(
|
|
136
|
-
Object.entries(branches).map(([key, BranchAgent]) => [
|
|
137
|
-
key,
|
|
138
|
-
async (ctx: BaseContext) => {
|
|
139
|
-
const inputText = resolveInput(mapInput, ctx)
|
|
140
|
-
const result = await new AgentRunner(BranchAgent).input(inputText).run()
|
|
141
|
-
assertCompleted(result, `${name}:${key}`)
|
|
142
|
-
addUsage(this.totalUsage, result.usage)
|
|
143
|
-
return result
|
|
144
|
-
},
|
|
145
|
-
])
|
|
146
|
-
)
|
|
147
|
-
)
|
|
148
|
-
return this
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Run an agent in a loop until a condition is met or max iterations reached.
|
|
153
|
-
* Use `feedback` to transform the result into the next iteration's input.
|
|
154
|
-
*/
|
|
155
|
-
loop(
|
|
156
|
-
name: string,
|
|
157
|
-
agent: new () => Agent,
|
|
158
|
-
options: {
|
|
159
|
-
maxIterations: number
|
|
160
|
-
until?: (result: AgentResult, iteration: number) => boolean
|
|
161
|
-
feedback?: (result: AgentResult) => string
|
|
162
|
-
mapInput?: StepMapInput
|
|
163
|
-
}
|
|
164
|
-
): this {
|
|
165
|
-
this.pipeline.loop(
|
|
166
|
-
name,
|
|
167
|
-
async (input: unknown, _ctx: BaseContext) => {
|
|
168
|
-
const result = await new AgentRunner(agent).input(String(input)).run()
|
|
169
|
-
assertCompleted(result, name)
|
|
170
|
-
addUsage(this.totalUsage, result.usage)
|
|
171
|
-
return result
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
maxIterations: options.maxIterations,
|
|
175
|
-
until: options.until
|
|
176
|
-
? (result: unknown, iteration: number) => options.until!(result as AgentResult, iteration)
|
|
177
|
-
: undefined,
|
|
178
|
-
feedback: options.feedback
|
|
179
|
-
? (result: unknown) => options.feedback!(result as AgentResult)
|
|
180
|
-
: undefined,
|
|
181
|
-
mapInput: options.mapInput
|
|
182
|
-
? (ctx: BaseContext) => resolveInput(options.mapInput, ctx)
|
|
183
|
-
: (ctx: BaseContext) => JSON.stringify(ctx.input),
|
|
184
|
-
}
|
|
185
|
-
)
|
|
186
|
-
return this
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** Execute the workflow. */
|
|
190
|
-
async run(input: Record<string, unknown>): Promise<WorkflowResult> {
|
|
191
|
-
this.totalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
|
192
|
-
const result = await this.pipeline.run(input)
|
|
193
|
-
return {
|
|
194
|
-
results: result.results as Record<string, AgentResult>,
|
|
195
|
-
usage: this.totalUsage,
|
|
196
|
-
duration: result.duration,
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|