main
rb 101 lines 3.36 KB
Raw
1 # frozen_string_literal: true
2
3 module Api
4 module V1
5 # siGit Code Cloud Sessions (Cloud Session): named, resumable conversations
6 # persisted server-side so they sync across the user's signed-in surfaces.
7 # Token-based, scoped to current_user; a user can only see and mutate their
8 # own sessions.
9 #
10 # GET /api/v1/sessions → list (most recent first)
11 # POST /api/v1/sessions → create { title?, model? }
12 # GET /api/v1/sessions/:id → session + messages
13 # PATCH /api/v1/sessions/:id → update { title?, model? }
14 # DELETE /api/v1/sessions/:id → 204
15 # POST /api/v1/sessions/:id/messages → append { role, content }
16 #
17 # Streaming inference is unchanged: the client still calls
18 # /api/v1/chat/completions. These endpoints only persist the transcript, so a
19 # session can be resumed later. Mapped at path "sessions" but kept a distinct
20 # controller from the auth SessionsController (sign_in/sign_out).
21 class CloudSessionsController < Api::BaseController
22 before_action :authenticate_token!
23 before_action :set_session, only: %i[show update destroy create_message]
24
25 def index
26 sessions = current_user.cloud_sessions.order(updated_at: :desc)
27 render json: sessions.map { |s| session_json(s) }, status: :ok
28 end
29
30 def create
31 session = current_user.cloud_sessions.create!(create_params)
32 render json: session_json(session), status: :created
33 end
34
35 def show
36 render json: session_json(@session, include_messages: true), status: :ok
37 end
38
39 def update
40 @session.update!(update_params)
41 render json: session_json(@session), status: :ok
42 end
43
44 def destroy
45 @session.destroy!
46 head :no_content
47 end
48
49 # Append one message to the session. The client persists the user message
50 # when it sends, and the assistant message once streaming completes.
51 def create_message
52 message = @session.append_message!(
53 role: message_params[:role],
54 content: message_params[:content]
55 )
56 render json: { session: session_json(@session.reload), message: message_json(message) },
57 status: :created
58 end
59
60 private
61
62 def set_session
63 @session = current_user.cloud_sessions.find_by(id: params[:id])
64 return if @session
65
66 render_error(ERR_INVALID, "Session not found.", status: :not_found)
67 end
68
69 def create_params
70 params.permit(:title, :model).to_h.slice("title", "model").compact_blank
71 end
72 alias update_params create_params
73
74 def message_params
75 params.permit(:role, :content)
76 end
77
78 def session_json(session, include_messages: false)
79 json = {
80 id: session.id,
81 title: session.title,
82 model: session.model,
83 last_message_at: session.last_message_at&.iso8601,
84 created_at: session.created_at.iso8601,
85 updated_at: session.updated_at.iso8601
86 }
87 json[:messages] = session.cloud_messages.map { |m| message_json(m) } if include_messages
88 json
89 end
90
91 def message_json(message)
92 {
93 id: message.id,
94 role: message.role,
95 content: message.content,
96 created_at: message.created_at.iso8601
97 }
98 end
99 end
100 end
101 end