Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
# whichever vitest worker hit it first and cascading into "0 test"
# failures across the rest of that worker's queue. Node 20 was
# already below what a fresh dependency needs; bump to match.
node-version: '22'
node-version: '22.19.0'
cache: 'npm'
- run: npm ci
- run: npx tsc --noEmit
Expand All @@ -34,6 +34,9 @@ jobs:
# which requires ITS dist/index.js to exist too - build it before the
# test step (this is a separate package from the root SDK above).
- run: npm run build --workspace=packages/create-loushy-agent
# Every ```ts block in README.md and docs/*.md must type-check against
# src/ (quick-start also runs against the packed tarball). Needs dist/.
- run: npm run docs:verify-snippets -- --skip-build
- run: npm run test:coverage
# Agent Forge (apps/agent-forge) imports the SDK as
# `@loushy/build-ai-agent` via `file:../..`, i.e. the root dist/ built
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ docs/api/
# fallow cache/snapshots
.fallow/

# docs snippet verifier temp dirs
.docs-snippets-*/
# Local agent worktrees and session state
.claude/
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ By participating in this project, you agree to maintain a respectful and inclusi

### Prerequisites

- Node.js >= 18.0.0
- Node.js >= 22.19.0
- npm, pnpm, or yarn

### Setup
Expand Down
42 changes: 28 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ const paused = await AgentExecutor.execute({
const result = await resumeAfterApproval(
{ id: paused.approvalId!, approved: true },
approvalStore,
provider,
registry,
provider,
);
```

Expand Down Expand Up @@ -240,16 +240,29 @@ registry.register('send_email', {
Flows orchestrate multi-step workflows within a single agent:

```typescript
import { FlowBuilder, FlowExecutor } from '@loushy/build-ai-agent';
import { FlowBuilder, FlowExecutor, type EditorStep } from '@loushy/build-ai-agent';

// FlowBuilder is a metadata builder: setCode/setName/setInputs/setFlow(...).build().
// The executable node types ('sequence', 'llmCall', 'oneOf', 'setVariable', ...) are
// those handled by FlowExecutor; EditorStep currently types the editor-side shapes,
// hence the cast.
const steps = {
type: 'sequence',
steps: [
{ type: 'llmCall', prompt: 'Classify this message as billing, technical or sales: {{message}}', outputVariable: 'category' },
{ type: 'llmCall', prompt: 'Write a one-line reply for a {{category}} request: {{message}}' },
],
} as unknown as EditorStep;

const flow = new FlowBuilder()
.addNode({ id: 'start', type: 'llm', data: { prompt: 'Analyze user input' } })
.addNode({ id: 'decide', type: 'conditional', data: { condition: 'output.sentiment === "positive"' } })
.addEdge('start', 'decide')
.setCode('triage')
.setName('Triage')
.addInput({ name: 'message', type: 'shortText', required: true })
.setFlow(steps)
.build();

// FlowExecutor is a static API too: execute(flow, context, onEvent?)
const result = await FlowExecutor.execute(flow, { agent, provider, variables: {} });
const result = await FlowExecutor.execute(flow, { agent, provider, variables: { message: input } });
```

### LLM Providers
Expand Down Expand Up @@ -298,8 +311,8 @@ const paused = await AgentExecutor.execute({
const result = await resumeAfterApproval(
{ id: paused.approvalId!, approved: true },
approvalStore,
provider,
toolRegistry,
provider,
);
```

Expand Down Expand Up @@ -386,9 +399,9 @@ if (!verdict.pass) {
### Tracing & observability

```typescript
import { AgentExecutor, withSpan } from '@loushy/build-ai-agent';
import { AgentExecutor, withSpan, type TraceExporter } from '@loushy/build-ai-agent';

const exporter = {
const exporter: TraceExporter = {
onSpanStart: (span) => console.log('[start]', span.name, span.attributes),
onSpanEnd: (span) => console.log('[end]', span.name, span.endTime! - span.startTime, 'ms'),
};
Expand Down Expand Up @@ -423,8 +436,8 @@ defineEval({
### MCP tools & sandboxing

```typescript
import { loadMcpTools } from '@loushy/build-ai-agent/tools/mcp/McpToolLoader';
import { SubprocessSandbox } from '@loushy/build-ai-agent';
import { loadMcpTools } from '@loushy/build-ai-agent/mcp';
import { AgentExecutor, SubprocessSandbox } from '@loushy/build-ai-agent';

// Turn any MCP server's tools into ToolDescriptors, namespaced <connection>__<tool>
const linearTools = await loadMcpTools(mcpClient, 'linear');
Expand All @@ -450,12 +463,13 @@ const hash = await sha256('password', 'salt');
### Storage

```typescript
import { StorageService } from '@loushy/build-ai-agent';
import { StorageService, type FileSystemAdapter } from '@loushy/build-ai-agent';
import fs from 'node:fs';
import path from 'node:path';

// fs/path are injected as typed adapters (LOU-A7) rather than `any`
const storage = new StorageService('user-123', 'attachments', fs, path);
// fs/path are injected as adapters (LOU-A7). Node's `fs` is structurally close
// but its writeFileSync options type is wider, so it needs a cast.
const storage = new StorageService('user-123', 'attachments', fs as unknown as FileSystemAdapter, path);

await storage.saveAttachment(file, 'document.pdf');
const buffer = storage.readAttachment('document.pdf');
Expand Down
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ its tools with `loadMcpTools()`, then pass the result to `createAgent()` (or
register it on a `ToolRegistry`):

```ts
import { createAgent } from '@loushy/build-ai-agent';
import { loadMcpTools } from '@loushy/build-ai-agent/mcp';

const tools = await loadMcpTools(mcpClient, 'my-server');
Expand Down
Loading
Loading