1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Channel session initialization
//!
//! When a messaging channel (Discord, Telegram, Slack, WhatsApp, Trello) needs
//! a new session — a fresh DM, a new group thread, a per-channel session — it
//! used to call `session_svc.create_session(title)` directly, which stamped
//! `provider_name = NULL` / `model = NULL`. Downstream, `sync_provider_for_session`
//! saw `None` and fell through to `config.active_provider_and_model()` — the
//! fixed priority list in config.toml — which does NOT reflect whatever the TUI
//! user had actively selected (TUI persists provider changes per-session, not
//! into config.toml).
//!
//! Net effect: a user who picked OpenRouter in the TUI would open Discord and
//! find the bot pinned to whatever provider happened to be first-enabled in
//! config.toml, not the one they were actually using.
//!
//! `create_channel_session` closes that gap: it creates the session and stamps
//! it with the most recent existing session's provider/model (falling back to
//! `None` if no such session exists, which then falls through to the config
//! priority list — the previous behavior). Call this instead of
//! `session_svc.create_session(...)` in every channel handler.
//!
//! Working directory is scoped differently on purpose (#263). Provider/model
//! come from the global most-recent session so a channel adopts whatever
//! provider the user last actively selected. The working directory, however,
//! comes ONLY from `inherit_wd_from`: the session that received the `/new`
//! command (or the idle-expired session being replaced) in this same chat.
//! Sourcing the cwd from the global most-recent session let a TUI session in
//! one directory bleed its cwd into an unrelated channel chat, so `/new` in a
//! Telegram group could silently adopt the directory the operator happened to
//! be using in the TUI. Same-chat scoping keeps within-chat continuity without
//! the cross-channel leak.
use Result;
use crateConfig;
use crateSession;
use crateSessionService;
/// Create a new channel session, inheriting provider + model from the most
/// recent existing session (TUI or any channel) when available, and the
/// working directory from `inherit_wd_from` — the session that received the
/// `/new` in this same chat (pass `None` for a brand-new chat with no prior
/// session).
///
/// Returns the created `Session`. Inheritance is best-effort: if the
/// most-recent-session lookup fails for any reason, the session is still
/// created with `provider_name = None` / `model = None`, matching the old
/// behavior so callers never fail because of this helper. When
/// `inherit_wd_from` is `None` or its session has no working directory, the
/// new session gets `working_directory = None`.
pub async
/// Route through the atomic insert-or-resolve path when the title carries a
/// stable `[chat:<id>]` suffix (#1721): two processes sharing one database
/// cannot be serialized by the in-process single-flight gate, so the unique
/// index decides and the loser joins the winner. Titles without a suffix
/// (should not happen on channel paths, but is legal for direct callers)
/// fall back to the plain insert.
async