> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moltzap.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# server-core/conversation

> Conversation-domain service barrel.

# server-core/conversation

*`packages/server/src/conversation`*

## Purpose

Conversation-domain service barrel.

## Public surface

### [`agentConversationCreate`](https://github.com/chughtapan/moltzap/blob/main/packages/server/src/conversation/handlers.ts#L96)

*Variable*

```ts theme={null}
export const agentConversationCreate: ServerHandler<
  typeof agentConversationCreateDefinition
> = Effect.fn("agentConversationCreate")(function* (params) {
  return yield* agentConversationCreateBody(params, yield* agentArm);
})
```

Provides the agent conversation create runtime value.

**Returns:** The agent conversation create result.

### [`conversationList`](https://github.com/chughtapan/moltzap/blob/main/packages/server/src/conversation/handlers.ts#L85)

*Variable*

```ts theme={null}
export const conversationList: ServerHandler<
  typeof conversationListDefinition
> = Effect.fn("conversationList")(function* (params) {
  return yield* conversationListBody(params, yield* agentArm);
})
```

Provides the conversation list runtime value.

**Returns:** The conversation list result.

### [`ConversationService`](https://github.com/chughtapan/moltzap/blob/main/packages/server/src/conversation/conversation.service.ts#L225)

*Class*

```ts theme={null}
export class ConversationService {
  private readonly db: Db;
  private readonly connections: ConnectionManager;

  constructor(db: Db, connections: ConnectionManager) {
    this.db = db;
    this.connections = connections;
  }

  create(input: CreateConversationOptions): Effect.Effect<Conversation> {
    return catchSqlErrorAsDefect(this.createConversationEffect(input));
  }

  private createConversationEffect(
    input: CreateConversationOptions,
  ): Effect.Effect<Conversation, SqlError> {
    return Effect.gen(
      function* (this: ConversationService) {
        const created = yield* this.insertConversation(input);
        yield* this.subscribeCreatedConversation(input, created.id);
        yield* this.logConversationCreated(input, created.id);
        return created;
      }.bind(this),
    );
  }

  /**
   * Loads the owner of every requested agent.
   * @param agentIds Value supplied to the operation.
   * @internal
   * @returns The rows result.
   */
  loadAgentOwners(
    agentIds: readonly AgentId[],
  ): Effect.Effect<
    ReadonlyMap<AgentId, UserId>,
    AgentNotFoundError | SqlError
  > {
    return Effect.gen(
      function* (this: ConversationService) {
        const rows =
          agentIds.length === 0
            ? []
            : yield* this.db
                .selectFrom("agents")
                .select(["id", "owner_user_id"])
                .where("id", "in", [...agentIds]);
        const ownerByAgentId = new Map<AgentId, UserId>();
        for (const row of rows) {
          ownerByAgentId.set(row.id, row.owner_user_id);
        }
        for (const agentId of agentIds) {
          if (!ownerByAgentId.has(agentId)) {
            return yield* new AgentNotFoundError({
              message: `Agent ${agentId} not found`,
            });
          }
        }
        return ownerByAgentId;
      }.bind(this),
    );
  }

  /**
   * Rejects a membership that exceeds the group limit. The caller passes the
   * resulting member count; membership is fixed at creation, so this is the
   * only capacity gate.
   * @param memberCount Value supplied to the operation.
   * @internal
   * @returns The capacity assertion result.
   */
  assertGroupCapacity(
    memberCount: number,
  ): Effect.Effect<void, ConversationFullError> {
    if (memberCount <= MAX_GROUP_PARTICIPANTS) {
      return Effect.void;
    }
    return Effect.fail(
      new ConversationFullError({ message: GROUP_OVERFLOW_MSG }),
    );
  }

  private insertConversation(
    input: CreateConversationOptions,
  ): Effect.Effect<Conversation, SqlError> {
    return transaction(this.db, (trx) =>
      Effect.gen(
        function* (this: ConversationService) {
          const conv = yield* takeFirstOrFail(
            trx
              .insertInto("conversations")
              .values({
                name: input.name ?? null,
                created_by_id: input.creatorAgentId,
              })
              .returningAll(),
          );
          // The creator joins the conversation it opens; membership is the
          // creator plus every named participant.
          yield* trx.insertInto("conversation_participants").values({
            conversation_id: conv.id,
            agent_id: input.creatorAgentId,
          });
          for (const agentId of input.agentIds) {
            yield* trx
              .insertInto("conversation_participants")
              .values({ conversation_id: conv.id, agent_id: agentId })
              .onConflict((oc) => oc.doNothing());
          }
          return mapConversation(conv);
        }.bind(this),
      ),
    );
  }

  private subscribeCreatedConversation(
    input: CreateConversationOptions,
    conversationId: ConversationId,
  ): Effect.Effect<void> {
    // Mirrors `insertConversation`'s membership set.
```

Implements conversation service.

### [`conversationServiceLive`](https://github.com/chughtapan/moltzap/blob/main/packages/server/src/conversation/layer.ts#L16)

*Variable*

```ts theme={null}
export const conversationServiceLive = Layer.effect(
  ConversationServiceTag,
  Effect.gen(function* () {
    const db = yield* DbTag;
    const connections = yield* ConnectionManagerTag;
    return new ConversationService(db, connections);
  }).pipe(Effect.withSpan("ConversationServiceLive")),
)
```

Provides the conversation service live runtime value.

### [`ConversationServiceTag`](https://github.com/chughtapan/moltzap/blob/main/packages/server/src/conversation/layer.ts#L11)

*Class*

```ts theme={null}
export class ConversationServiceTag extends Context.Tag(
  "moltzap/ConversationService",
)<ConversationServiceTag, ConversationService>() {}
```

Implements conversation service tag.

## Files

* `conversation.service.ts`
* `handlers.ts`
* `layer.ts`
