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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `createAgent()` agents can pause for approval (LOU-D21): a `needsApproval` tool no longer fails the run with "requires approval but no approvalStore". The run pauses (`finishReason: 'awaiting-approval'`) in a per-agent `InMemoryApprovalStore` (or the new `approvalStore` option), and `agent.approvals.list()` / `agent.approvals.resolve({ id, approved, note? })` continue it, in its session if it paused in one. The `approve` option decides calls in code without pausing.

### Changed
- `AgentType` is optional and deprecated (LOU-D34, not breaking): `AgentBuilder.build()` no longer requires `setType()` and `AgentConfig.agentType` is now optional (`createAgent()` and `specToAgent()` agents carry no type). `AgentType`, `setType()` and the `agent-types` registry/validators are marked `@deprecated`: they have no runtime effect and will be removed in the next minor; they stay exported for now. Drop your `setType(...)` calls.
- BREAKING: `encrypt()` now generates a random salt per call instead of a hardcoded one. Ciphertext produced before this change cannot be decrypted with the new code and must be re-encrypted.
- BREAKING: The mock repositories (`MockAgentRepository`, `MockSessionRepository`, `MockResultRepository`, `MockMemoryRepository`, `MockAttachmentRepository` — previously re-exported from `src/data/mocks.ts` via the package root/`./data` subpath; this package has no `createMockRepositories` factory) are no longer exported from the package root. Import them from `@loushy/build-ai-agent/testing` instead.

Expand Down
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,9 @@ you need `maxSteps`, approval gates, checkpoints, tracing hooks, or a
API — there is no `new AgentExecutor()`.

```typescript
import { AgentBuilder, AgentExecutor, AgentType, resolveProvider } from '@loushy/build-ai-agent';
import { AgentBuilder, AgentExecutor, resolveProvider } from '@loushy/build-ai-agent';

const agent = AgentBuilder.create()
.setType(AgentType.SmartAssistant)
.setName('Customer Support Agent')
.setPrompt('You are a helpful customer support assistant.')
.build();
Expand Down Expand Up @@ -280,7 +279,7 @@ Both files are generated (`npm run docs:llms`) and checked in CI.

### Agents

Agents combine a **type** (`AgentType.SmartAssistant`, etc.), a **prompt**,
Agents combine a **prompt**,
**tools**, optional **flows**, and conversation **memory**. Build one with
`createAgent()` for the common case, or `AgentBuilder` when you need full
control over the resulting `AgentConfig`.
Expand Down Expand Up @@ -476,11 +475,10 @@ To wire one child `AgentConfig` as a tool yourself, use `createDelegateTool()`
run the same way):

```typescript
import { AgentExecutor, createDelegateTool, ToolRegistry, AgentType } from '@loushy/build-ai-agent';
import { AgentExecutor, createDelegateTool, ToolRegistry } from '@loushy/build-ai-agent';

const billingAgent = {
name: 'Billing Agent',
agentType: AgentType.SmartAssistant,
prompt: 'You answer billing questions and look up invoices.',
};

Expand All @@ -498,7 +496,6 @@ registry.register(

const supportAgent = {
name: 'Support Agent',
agentType: AgentType.SmartAssistant,
prompt: 'You help customers. Delegate billing questions to the billing agent.',
tools: { delegate_billing_agent: { tool: 'delegate_billing_agent' } },
};
Expand Down
2 changes: 1 addition & 1 deletion docs/api-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ npm run docs:build # writes docs/api/index.html
| `createAgent(config)` | Zero-config `{ send(message) }` agent from a `model` string or provider (+ instructions, tools). |
| `AgentBuilder` | Fluent builder for an `AgentConfig` (`AgentBuilder.create().setName(...)...build()`). |
| `AgentExecutor.execute(opts)` | Static executor: runs an agent (LLM + tool-calling loop) and resolves to an `ExecutionResult`. |
| `AgentType` | Agent type enum (e.g. `AgentType.SmartAssistant`). |
| `AgentType` | Deprecated, no runtime effect: agents need no type (removed next minor). |
| `resumeAfterApproval()` | Resume an execution paused for human approval. |
| `InMemoryApprovalStore` | Process-local `ApprovalStore`; the default store of `createAgent()` agents. |
| `SessionAwaitingApprovalError` | Thrown by `execute()` when its `sessionId` is paused on an approval (see [Durable execution](./durable-execution.md)). |
Expand Down
2 changes: 0 additions & 2 deletions docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,10 @@ checkpoints, tracing, ...). `AgentExecutor` is a static API - there is no
import {
AgentBuilder,
AgentExecutor,
AgentType,
createMockProvider,
} from '@loushy/build-ai-agent';

const agent = AgentBuilder.create()
.setType(AgentType.SmartAssistant)
.setName('Customer Support Agent')
.setPrompt('You are a helpful customer support assistant.')
.build();
Expand Down
13 changes: 4 additions & 9 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,9 @@ you need `maxSteps`, approval gates, checkpoints, tracing hooks, or a
API — there is no `new AgentExecutor()`.

```typescript
import { AgentBuilder, AgentExecutor, AgentType, resolveProvider } from '@loushy/build-ai-agent';
import { AgentBuilder, AgentExecutor, resolveProvider } from '@loushy/build-ai-agent';

const agent = AgentBuilder.create()
.setType(AgentType.SmartAssistant)
.setName('Customer Support Agent')
.setPrompt('You are a helpful customer support assistant.')
.build();
Expand Down Expand Up @@ -278,7 +277,7 @@ Both files are generated (`npm run docs:llms`) and checked in CI.

### Agents

Agents combine a **type** (`AgentType.SmartAssistant`, etc.), a **prompt**,
Agents combine a **prompt**,
**tools**, optional **flows**, and conversation **memory**. Build one with
`createAgent()` for the common case, or `AgentBuilder` when you need full
control over the resulting `AgentConfig`.
Expand Down Expand Up @@ -474,11 +473,10 @@ To wire one child `AgentConfig` as a tool yourself, use `createDelegateTool()`
run the same way):

```typescript
import { AgentExecutor, createDelegateTool, ToolRegistry, AgentType } from '@loushy/build-ai-agent';
import { AgentExecutor, createDelegateTool, ToolRegistry } from '@loushy/build-ai-agent';

const billingAgent = {
name: 'Billing Agent',
agentType: AgentType.SmartAssistant,
prompt: 'You answer billing questions and look up invoices.',
};

Expand All @@ -496,7 +494,6 @@ registry.register(

const supportAgent = {
name: 'Support Agent',
agentType: AgentType.SmartAssistant,
prompt: 'You help customers. Delegate billing questions to the billing agent.',
tools: { delegate_billing_agent: { tool: 'delegate_billing_agent' } },
};
Expand Down Expand Up @@ -1128,12 +1125,10 @@ checkpoints, tracing, ...). `AgentExecutor` is a static API - there is no
import {
AgentBuilder,
AgentExecutor,
AgentType,
createMockProvider,
} from '@loushy/build-ai-agent';

const agent = AgentBuilder.create()
.setType(AgentType.SmartAssistant)
.setName('Customer Support Agent')
.setPrompt('You are a helpful customer support assistant.')
.build();
Expand Down Expand Up @@ -1219,7 +1214,7 @@ npm run docs:build # writes docs/api/index.html
| `createAgent(config)` | Zero-config `{ send(message) }` agent from a `model` string or provider (+ instructions, tools). |
| `AgentBuilder` | Fluent builder for an `AgentConfig` (`AgentBuilder.create().setName(...)...build()`). |
| `AgentExecutor.execute(opts)` | Static executor: runs an agent (LLM + tool-calling loop) and resolves to an `ExecutionResult`. |
| `AgentType` | Agent type enum (e.g. `AgentType.SmartAssistant`). |
| `AgentType` | Deprecated, no runtime effect: agents need no type (removed next minor). |
| `resumeAfterApproval()` | Resume an execution paused for human approval. |
| `InMemoryApprovalStore` | Process-local `ApprovalStore`; the default store of `createAgent()` agents. |
| `SessionAwaitingApprovalError` | Thrown by `execute()` when its `sessionId` is paused on an approval (see [Durable execution](https://github.com/LinuxDevil/agent-sdk/blob/main/docs/durable-execution.md)). |
Expand Down
50 changes: 17 additions & 33 deletions src/agent-types/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,62 @@ import { AgentType, AgentTypeDescriptor } from '../types';
/**
* Agent types registry
* Contains all available agent type descriptors
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export const agentTypesRegistry: AgentTypeDescriptor[] = [
{
type: AgentType.SmartAssistant,
description: {
ar: "المساعدون الأذكياء هم **وكلاء متعددو الأغراض**. يمكنهم استخدام الأدوات، على سبيل المثال، للتحقق من التقويم الخاص بك أو حجز أحداث جديدة. يمكن استخدامها أيضًا للاستطلاعات (مع مهام أخرى) ولكن يجب تخصيصها للقيام بذلك على مستوى الموجه.",
en: "Smart assistants are **general-purpose agents**. They can use tools, for example, checking your calendar or booking new events. They can also be used for surveys (mixed with other tasks) but need to be fine-tuned for doing so at the prompt level."
},
description: { en: 'General-purpose agent that can use tools.' },
supportsUserFacingUI: true,
requiredTabs: ['prompt', 'expectedResult'],
displayName: {
'ar': 'مساعد ذكي [محادثة]',
'en': 'Smart assistant [Chat]'
}
displayName: { en: 'Smart assistant [Chat]' },
},
{
type: AgentType.SurveyAgent,
description: {
ar: "يتم استخدام وكلاء الاستطلاع لجمع المعلومات أو الآراء من المستخدمين. بناءً على الإجابات السابقة، يمكنهم **ضبط الأسئلة التالية ديناميكيًا**. يحفظ هؤلاء الوكلاء الإجابات لمزيد من المعالجة بالتنسيق المطلوب. يمكنهم استبدال أدوات مثل **النماذج، الاستطلاعات، نماذج التسجيل** وما إلى ذلك.",
en: "Survey agents are used to collect information or opinions from users. Based on previous answers, they can **dynamically adjust** the next questions. These agents save the answers for further processing in the desired format. They can replace tools like **Forms, Polls, Intake forms** etc."
},
description: { en: 'Collects information from users and adapts follow-up questions.' },
supportsUserFacingUI: true,
requiredTabs: ['prompt', 'expectedResult'],
displayName: {
'ar': 'وكيل استطلاع [محادثة]',
'en': 'Survey agent [Chat]'
}
displayName: { en: 'Survey agent [Chat]' },
},
{
type: AgentType.CommerceAgent,
description: {
ar: "يُستخدم الوكلاء التجاريون **لبيع المنتجات أو الخدمات**. يمكن استخدامها في **التجارة الإلكترونية**، **حجز الخدمات**، سيناريوهات **b2b/cpq**. يعملون على **كتالوج المنتجات** ويمكن استخدامها **للبيع الإضافي** أو **البيع المتقاطع** للمنتجات.",
en: "Commerce agents are used to **sell products or services**. They can be used in **e-commerce**, **service booking**, **b2b/cpq** scenarios. They operate on the **product catalog** and can be used to **upsell** or **cross-sell** products."
},
description: { en: 'Sells products or services from a catalog.' },
supportsUserFacingUI: true,
requiredTabs: ['prompt', 'expectedResult'],
displayName: {
'ar': 'مساعد مبيعات [محادثة]',
'en': 'Sales assistant [Chat]'
}
displayName: { en: 'Sales assistant [Chat]' },
},
{
type: AgentType.Flow,
description: {
ar: "تتيح لك الوكلاء المعتمدون على التدفق إنشاء **سيناريوهات معقدة**. يمكن استخدامها **لأتمتة العمليات** وتطوير التطبيقات التي يتم استدعاؤها بواسطة API أو وكلاء آخرين، باستخدام **اللغة الطبيعية**. يمكن استخدامها **لإنشاء أشجار القرار** أو **التكاملات**.",
en: "Flow-based agents let you create **complex scenarios**. They can be used to **automate processes** and develop apps that are called by API or other agents, using **natural language**. They can be used to **create decision trees** or **integrations**."
},
description: { en: 'Runs multi-step scenarios called by an API or other agents.' },
supportsUserFacingUI: true,
requiredTabs: [],
displayName: {
'ar': 'تطبيق / سير عمل [API]',
'en': 'App / Workflow [API]'
}
}
displayName: { en: 'App / Workflow [API]' },
},
];

/**
* Get agent type descriptor by type
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export function getAgentTypeDescriptor(type: AgentType): AgentTypeDescriptor | undefined {
return agentTypesRegistry.find(descriptor => descriptor.type === type);
}

/**
* Get all agent type descriptors
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export function getAllAgentTypeDescriptors(): AgentTypeDescriptor[] {
return [...agentTypesRegistry];
}

/**
* Check if agent type is valid
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export function isValidAgentType(type: string): type is AgentType {
return agentTypesRegistry.some(descriptor => descriptor.type === type);
Expand Down
12 changes: 7 additions & 5 deletions src/agent-types/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

/**
* Validate agent configuration
*
* `agentType` is optional; it is only checked when present.
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export function validateAgentConfig(config: Partial<AgentConfig>): { valid: boolean; errors: string[] } {
const errors: string[] = [];
Expand All @@ -16,11 +20,7 @@
);
}

if (!config.agentType) {
errors.push(
'Agent type is required. Example: AgentBuilder.create().setType(AgentType.SmartAssistant)...build()'
);
} else if (!Object.values(AgentType).includes(config.agentType)) {
if (config.agentType !== undefined && !Object.values(AgentType).includes(config.agentType)) {
errors.push(`Invalid agent type: ${config.agentType}`);
}

Expand All @@ -32,8 +32,10 @@

/**
* Validate agent tools configuration
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export function validateAgentTools(tools: Record<string, any>): { valid: boolean; errors: string[] } {

Check warning on line 38 in src/agent-types/validators.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
const errors: string[] = [];

for (const [key, config] of Object.entries(tools)) {
Expand Down
18 changes: 12 additions & 6 deletions src/core/AgentBuilder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,24 @@ describe('AgentBuilder', () => {
}).toThrow('Agent name is required');
});

it('should throw error when type is missing', () => {
it('builds without setType() (agentType is optional and deprecated)', () => {
const agent = new AgentBuilder().setName('Test Agent').build();

expect(agent.name).toBe('Test Agent');
expect(agent.agentType).toBeUndefined();
expect('agentType' in agent).toBe(false);
});

it('still rejects an invalid agent type when one is provided', () => {
expect(() => {
new AgentBuilder()
.setName('Test Agent')
.build();
}).toThrow('Agent type is required');
AgentBuilder.from({ name: 'Test Agent', agentType: 'bogus' as AgentType }).build();
}).toThrow('Invalid agent type: bogus');
});

it('names the missing field and shows a corrective snippet (LOU-H12)', () => {
expect(() => {
new AgentBuilder().build();
}).toThrow(/Agent name is required\. Example:.*Agent type is required\. Example:/s);
}).toThrow(/Agent name is required\. Example: AgentBuilder\.create\(\)\.setName\('my-agent'\)/);
});

it('should add tools correctly', () => {
Expand Down
5 changes: 4 additions & 1 deletion src/core/AgentBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

/**
* Set agent type
*
* @deprecated Has no runtime effect and will be removed in the next minor
* release. `build()` no longer requires a type; just drop this call.
*/
public setType(type: AgentType): this {
this.config.agentType = type;
Expand Down Expand Up @@ -106,7 +109,7 @@
/**
* Set expected result schema
*/
public setExpectedResult(schema: any): this {

Check warning on line 112 in src/core/AgentBuilder.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
this.config.expectedResult = schema;
return this;
}
Expand All @@ -122,7 +125,7 @@
/**
* Set events
*/
public setEvents(events: any[]): this {

Check warning on line 128 in src/core/AgentBuilder.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
this.config.events = events;
return this;
}
Expand All @@ -130,7 +133,7 @@
/**
* Set settings
*/
public setSettings(settings: Record<string, any>): this {

Check warning on line 136 in src/core/AgentBuilder.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
this.config.settings = settings;
return this;
}
Expand All @@ -138,7 +141,7 @@
/**
* Set metadata
*/
public setMetadata(metadata: Record<string, any>): this {

Check warning on line 144 in src/core/AgentBuilder.ts

View workflow job for this annotation

GitHub Actions / ci

Unexpected any. Specify a different type
this.config.metadata = metadata;
return this;
}
Expand All @@ -152,7 +155,7 @@
return {
id: this.config.id || nanoid(),
name: this.config.name!,
agentType: this.config.agentType!,
...(this.config.agentType !== undefined && { agentType: this.config.agentType }),
locale: this.config.locale || 'en',
prompt: this.config.prompt,
expectedResult: this.config.expectedResult,
Expand Down
2 changes: 0 additions & 2 deletions src/createAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/

import { AgentBuilder } from './core/AgentBuilder';
import { AgentType } from './types';
import { AgentExecutor, ExecuteOptions, ExecutionResult } from './execution/AgentExecutor';
import type { AgentRun } from './execution/agentRun';
import { LLMProvider } from './providers/llm';
Expand Down Expand Up @@ -290,7 +289,6 @@ export function createAgent(config: CreateAgentConfig = {}): SimpleAgent {
const { toolRegistry, toolsConfig } = registerTools(config.tools ?? {});

const builder = AgentBuilder.create()
.setType(AgentType.SmartAssistant)
.setName(config.name || 'agent')
.setPrompt(instructions)
.setTools(toolsConfig);
Expand Down
2 changes: 1 addition & 1 deletion src/data/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { AgentConfig, AgentFlow } from '../types';
export class Agent {
id?: string;
name: string;
agentType: string;
agentType?: string;
locale: string;
prompt?: string;
expectedResult?: any;
Expand Down
3 changes: 1 addition & 2 deletions src/deploy/specExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* resolving providers/tools in a way that works on its own platform.
*/
import { AgentBuilder } from '../core/AgentBuilder';
import { AgentType, ToolConfiguration, ToolDescriptor } from '../types';
import { ToolConfiguration, ToolDescriptor } from '../types';
import { ToolRegistry } from '../tools/ToolRegistry';
import { ExecuteOptions } from '../execution/AgentExecutor';
import { LLMProvider } from '../providers/llm';
Expand Down Expand Up @@ -37,7 +37,6 @@ export function prepareSpecExecution(spec: AgentSpec, resolvers: SpecResolvers):
}

const agent = AgentBuilder.create()
.setType(AgentType.SmartAssistant)
.setName(spec.name)
.setPrompt(spec.prompt)
.setTools(toolsConfig)
Expand Down
8 changes: 7 additions & 1 deletion src/types/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { AgentFlow } from './flow';

/**
* Agent type identifiers
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
* Agents no longer need a type; omit `setType()` / `agentType`.
*/
export enum AgentType {
SmartAssistant = 'smart-assistant',
Expand All @@ -14,6 +17,8 @@ export enum AgentType {

/**
* Agent type descriptor
*
* @deprecated Has no runtime effect and will be removed in the next minor release.
*/
export interface AgentTypeDescriptor {
type: AgentType;
Expand All @@ -29,7 +34,8 @@ export interface AgentTypeDescriptor {
export interface AgentConfig {
id?: string;
name: string;
agentType: AgentType;
/** @deprecated Optional and ignored at runtime; will be removed in the next minor release. */
agentType?: AgentType;
locale?: string;
prompt?: string;
expectedResult?: any;
Expand Down
Loading