CreateChat creates a chat, inserts optional system prompt and initial user message, and moves the chat into pending status.
(ctx context.Context, opts CreateOptions)
| 1541 | // CreateChat creates a chat, inserts optional system prompt and initial user |
| 1542 | // message, and moves the chat into pending status. |
| 1543 | func (p *Server) CreateChat(ctx context.Context, opts CreateOptions) (database.Chat, error) { |
| 1544 | if opts.OrganizationID == uuid.Nil { |
| 1545 | return database.Chat{}, xerrors.New("organization_id is required") |
| 1546 | } |
| 1547 | if opts.OwnerID == uuid.Nil { |
| 1548 | return database.Chat{}, xerrors.New("owner_id is required") |
| 1549 | } |
| 1550 | if strings.TrimSpace(opts.Title) == "" { |
| 1551 | return database.Chat{}, xerrors.New("title is required") |
| 1552 | } |
| 1553 | if len(opts.InitialUserContent) == 0 { |
| 1554 | return database.Chat{}, xerrors.New("initial user content is required") |
| 1555 | } |
| 1556 | // Ensure MCPServerIDs is non-nil so pq.Array produces '{}' |
| 1557 | // instead of SQL NULL, which violates the NOT NULL column |
| 1558 | // constraint. |
| 1559 | if opts.MCPServerIDs == nil { |
| 1560 | opts.MCPServerIDs = []uuid.UUID{} |
| 1561 | } |
| 1562 | if opts.Labels == nil { |
| 1563 | opts.Labels = database.StringMap{} |
| 1564 | } |
| 1565 | // Resolve the deployment prompt before opening the transaction so |
| 1566 | // chat creation does not hold one DB connection while waiting for |
| 1567 | // another pool checkout. |
| 1568 | deploymentPrompt := p.resolveDeploymentSystemPrompt(ctx) |
| 1569 | |
| 1570 | effectivePlanMode := opts.PlanMode |
| 1571 | opts.ClientType = cmp.Or(opts.ClientType, database.ChatClientTypeApi) |
| 1572 | if !opts.ClientType.Valid() { |
| 1573 | return database.Chat{}, xerrors.Errorf("invalid client_type: %q", opts.ClientType) |
| 1574 | } |
| 1575 | var chat database.Chat |
| 1576 | txErr := p.db.InTx(func(tx database.Store) error { |
| 1577 | if limitErr := p.checkUsageLimit(ctx, tx, opts.OwnerID, uuid.NullUUID{UUID: opts.OrganizationID, Valid: true}); limitErr != nil { |
| 1578 | return limitErr |
| 1579 | } |
| 1580 | |
| 1581 | labelsJSON, err := json.Marshal(opts.Labels) |
| 1582 | if err != nil { |
| 1583 | return xerrors.Errorf("marshal labels: %w", err) |
| 1584 | } |
| 1585 | |
| 1586 | insertedChat, err := tx.InsertChat(ctx, database.InsertChatParams{ |
| 1587 | OrganizationID: opts.OrganizationID, |
| 1588 | OwnerID: opts.OwnerID, |
| 1589 | WorkspaceID: opts.WorkspaceID, |
| 1590 | BuildID: opts.BuildID, |
| 1591 | AgentID: opts.AgentID, |
| 1592 | ParentChatID: opts.ParentChatID, |
| 1593 | RootChatID: opts.RootChatID, |
| 1594 | LastModelConfigID: opts.ModelConfigID, |
| 1595 | Title: opts.Title, |
| 1596 | Mode: opts.ChatMode, |
| 1597 | PlanMode: effectivePlanMode, |
| 1598 | ClientType: opts.ClientType, |
| 1599 | // Chats created with an initial user message start pending. |
| 1600 | // Waiting is reserved for idle chats with no pending work. |
nothing calls this directly
no test coverage detected