diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd32e13f..3818b3858 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 0fea82fe6..0c404b2c5 100644 --- a/README.md +++ b/README.md @@ -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(); @@ -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`. @@ -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.', }; @@ -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' } }, }; diff --git a/docs/api-overview.md b/docs/api-overview.md index 04ab1e11b..11732eff6 100644 --- a/docs/api-overview.md +++ b/docs/api-overview.md @@ -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)). | diff --git a/docs/quick-start.md b/docs/quick-start.md index 845c4d219..8acf225c5 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -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(); diff --git a/llms-full.txt b/llms-full.txt index 9362bd07a..c62008148 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -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(); @@ -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`. @@ -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.', }; @@ -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' } }, }; @@ -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(); @@ -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)). | diff --git a/src/agent-types/registry.ts b/src/agent-types/registry.ts index ff6ef1078..8f9548956 100644 --- a/src/agent-types/registry.ts +++ b/src/agent-types/registry.ts @@ -3,64 +3,44 @@ 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); @@ -68,6 +48,8 @@ export function getAgentTypeDescriptor(type: AgentType): AgentTypeDescriptor | u /** * 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]; @@ -75,6 +57,8 @@ export function getAllAgentTypeDescriptors(): AgentTypeDescriptor[] { /** * 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); diff --git a/src/agent-types/validators.ts b/src/agent-types/validators.ts index f38f4a653..2f770de9f 100644 --- a/src/agent-types/validators.ts +++ b/src/agent-types/validators.ts @@ -6,6 +6,10 @@ function isBlank(value: string | undefined): boolean { /** * 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): { valid: boolean; errors: string[] } { const errors: string[] = []; @@ -16,11 +20,7 @@ export function validateAgentConfig(config: Partial): { valid: bool ); } - 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}`); } @@ -32,6 +32,8 @@ export function validateAgentConfig(config: Partial): { valid: bool /** * Validate agent tools configuration + * + * @deprecated Has no runtime effect and will be removed in the next minor release. */ export function validateAgentTools(tools: Record): { valid: boolean; errors: string[] } { const errors: string[] = []; diff --git a/src/core/AgentBuilder.test.ts b/src/core/AgentBuilder.test.ts index ed84e0fab..074c85cbd 100644 --- a/src/core/AgentBuilder.test.ts +++ b/src/core/AgentBuilder.test.ts @@ -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', () => { diff --git a/src/core/AgentBuilder.ts b/src/core/AgentBuilder.ts index 196e10e96..671adcd59 100644 --- a/src/core/AgentBuilder.ts +++ b/src/core/AgentBuilder.ts @@ -11,6 +11,9 @@ export class AgentBuilder { /** * 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; @@ -152,7 +155,7 @@ export class AgentBuilder { 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, diff --git a/src/createAgent.ts b/src/createAgent.ts index 8e1b898fc..0da8a34e6 100644 --- a/src/createAgent.ts +++ b/src/createAgent.ts @@ -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'; @@ -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); diff --git a/src/data/models.ts b/src/data/models.ts index e20a230f1..2e294893c 100644 --- a/src/data/models.ts +++ b/src/data/models.ts @@ -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; diff --git a/src/deploy/specExecution.ts b/src/deploy/specExecution.ts index 367b1cf94..e8a4fadcb 100644 --- a/src/deploy/specExecution.ts +++ b/src/deploy/specExecution.ts @@ -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'; @@ -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) diff --git a/src/types/agent.ts b/src/types/agent.ts index 9fc64c9ab..0a82f7f43 100644 --- a/src/types/agent.ts +++ b/src/types/agent.ts @@ -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', @@ -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; @@ -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;