Daydreams Logo
Extra reading

serviceProvider.ts

This file provides the service helper function, which you use to define how shared resources or external clients (like an API client, database connection, or special utility) should be managed by the Daydreams framework. It ensures these services are set up correctly and are ready to use when your agent needs them.

How to Use

You typically define a service in its own file using service({...}) and then include it in an Extension. Inside the service({...}) call, you can define:

  • register(container): (Optional) A function where you tell the agent's DI Container (agent.container) how to create this service instance. Often, you'll use container.singleton('serviceName', () => new MyServiceClient(...)) here to ensure only one instance is created.
  • boot(container): (Optional) An async function where you perform any necessary initialization after all services have been registered (e.g., connecting to the API using credentials maybe resolved from the container). This runs when agent.start() is called.
import { service, type Container } from "@daydreamsai/core";
 
// Assume MyApiClient class exists
declare class MyApiClient {
  constructor(config: { url: string });
  connect(): Promise<void>;
}
 
export const myApiService = service({
  register(container: Container) {
    // Tell the container how to create the client (as a singleton)
    container.singleton(
      "myApiClient",
      () => new MyApiClient({ url: "https://api.example.com" })
    );
  },
  async boot(container: Container) {
    // Initialize the client after registration
    const client = container.resolve<MyApiClient>("myApiClient");
    await client.connect();
    console.log("My API Client connected!");
  },
});
 
// Typically, you would then include `myApiService` in an extension's `services` array.

Benefit

Defining services this way ensures proper setup and teardown, especially for resources needing asynchronous initialization (boot). It integrates smoothly with the DI Container, making services easily accessible via agent.container.resolve('serviceName') in your actions or other components, without them needing to know the setup details. Bundling services in Extensions makes them reusable.

Anticipated Questions

  • "When should I use a service vs just putting logic in an action?" Use a service for shared, reusable components, especially those managing connections to external systems or requiring specific setup/initialization steps (boot). Actions are better for defining specific tasks the agent can perform, which might use one or more services obtained from the container.
  • "What's the difference between register and boot?" register runs first and only tells the container how to create the service. boot runs later (during agent.start()) and performs the actual initialization (like connecting), potentially using other services that were registered earlier.
  • "Do I need to call createServiceManager()?" No, this is handled internally by createDreams. You just define your services using the service helper.

On this page