Merge nucleic/sleek-slate-ferret into dev
This commit is contained in:
@@ -121,10 +121,13 @@ final class RemoteStore: ObservableObject {
|
|||||||
return (descriptor, candidates)
|
return (descriptor, candidates)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch a new chat to the abstract **Mesh** destination from the phone: rank eligible
|
/// Dispatch a new chat to the abstract **Carbon** destination from the phone: rank eligible
|
||||||
/// hosts by the shared scorer and try them in order, one at a time with a correlated,
|
/// hosts by the shared scorer and try them in order, one at a time with a correlated,
|
||||||
/// idempotent ack (a timeout retries the same candidate once before moving on). On success
|
/// idempotent ack (a timeout retries the same candidate once before moving on). On success
|
||||||
/// routes to the landed session. Mirrors `AppStore.dispatchChatToMesh`.
|
/// routes to the landed session. Mirrors `AppStore.dispatchChatToMesh`. The phone stamps
|
||||||
|
/// itself as the Carbon origin, so the landed session is Carbon-managed (its owner keeps it
|
||||||
|
/// on the optimal host between turns); the phone can't own sessions, so the origin exclusion
|
||||||
|
/// is naturally satisfied by every candidate.
|
||||||
func dispatchChatToMesh(
|
func dispatchChatToMesh(
|
||||||
projectID: ProjectID, message: String, model: String? = nil,
|
projectID: ProjectID, message: String, model: String? = nil,
|
||||||
effort: String? = nil, auto: Bool? = nil
|
effort: String? = nil, auto: Bool? = nil
|
||||||
@@ -141,8 +144,8 @@ final class RemoteStore: ObservableObject {
|
|||||||
backend: nil, excluding: excluded).first
|
backend: nil, excluding: excluded).first
|
||||||
else {
|
else {
|
||||||
showError(tried == 0
|
showError(tried == 0
|
||||||
? "No mesh runner can take this chat right now."
|
? "No Carbon host can take this chat right now."
|
||||||
: "No mesh runner could take this chat (\(tried) tried).", sessionID: nil)
|
: "No Carbon host could take this chat (\(tried) tried).", sessionID: nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tried += 1
|
tried += 1
|
||||||
@@ -154,7 +157,8 @@ final class RemoteStore: ObservableObject {
|
|||||||
let requestID = UUID().uuidString
|
let requestID = UUID().uuidString
|
||||||
let request = StartChatRequest(
|
let request = StartChatRequest(
|
||||||
projectID: targetProjectID, message: text, model: model, effort: effort,
|
projectID: targetProjectID, message: text, model: model, effort: effort,
|
||||||
auto: auto, requestID: requestID)
|
auto: auto, requestID: requestID,
|
||||||
|
carbonOriginDeviceID: IdentityStore.deviceID())
|
||||||
var outcome = await sendDispatch(request, on: conn, timeout: .seconds(10))
|
var outcome = await sendDispatch(request, on: conn, timeout: .seconds(10))
|
||||||
if outcome == nil {
|
if outcome == nil {
|
||||||
outcome = await sendDispatch(request, on: conn, timeout: .seconds(5))
|
outcome = await sendDispatch(request, on: conn, timeout: .seconds(5))
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ struct StartChatComposer: View {
|
|||||||
/// project page's "+", so the chat always lands in that project.
|
/// project page's "+", so the chat always lands in that project.
|
||||||
var lockedProject: WireProject? = nil
|
var lockedProject: WireProject? = nil
|
||||||
@State private var projectID: ProjectID?
|
@State private var projectID: ProjectID?
|
||||||
/// Mesh dispatch: run on the project's own Mac (false) or auto-route to the best eligible
|
/// Carbon (mesh work queue): run on the project's own Mac (false) or on Carbon (true) —
|
||||||
/// mesh host (true). Shown only when a connected peer could actually take it.
|
/// auto-routed to the best eligible mesh host and kept on the optimal host between turns.
|
||||||
|
/// The phone itself can't run sessions, so every Carbon candidate is already "not here".
|
||||||
|
/// Shown only when a connected peer could actually take it.
|
||||||
@State private var runOnMesh = false
|
@State private var runOnMesh = false
|
||||||
@State private var autoOverride: Bool?
|
@State private var autoOverride: Bool?
|
||||||
@State private var model: String?
|
@State private var model: String?
|
||||||
@@ -87,18 +89,19 @@ struct StartChatComposer: View {
|
|||||||
? "Auto-approve is always on for Nucleic Control chats — they run autonomously."
|
? "Auto-approve is always on for Nucleic Control chats — they run autonomously."
|
||||||
: "Auto-approve safe actions; destructive ones still ask.")
|
: "Auto-approve safe actions; destructive ones still ask.")
|
||||||
}
|
}
|
||||||
// Mesh dispatch: when an eligible peer holds this repo, offer "Auto (Mesh)" so the
|
// Carbon (mesh work queue): when an eligible peer holds this repo, offer "Carbon" so
|
||||||
// chat routes to whichever host fits rather than always its own owner.
|
// the chat routes to whichever host fits — and moves between hosts as availability
|
||||||
|
// changes — rather than always running on its own owner.
|
||||||
if meshAvailable {
|
if meshAvailable {
|
||||||
Menu {
|
Menu {
|
||||||
Picker("Run on", selection: $runOnMesh) {
|
Picker("Run on", selection: $runOnMesh) {
|
||||||
Text("This Mac").tag(false)
|
Text("This Mac").tag(false)
|
||||||
Text("Mesh (automatic)").tag(true)
|
Text("Carbon").tag(true)
|
||||||
}
|
}
|
||||||
.pickerStyle(.inline)
|
.pickerStyle(.inline)
|
||||||
} label: {
|
} label: {
|
||||||
Label(
|
Label(
|
||||||
runOnMesh ? "Mesh" : "This Mac",
|
runOnMesh ? "Carbon" : "This Mac",
|
||||||
systemImage: runOnMesh ? "antenna.radiowaves.left.and.right" : "desktopcomputer")
|
systemImage: runOnMesh ? "antenna.radiowaves.left.and.right" : "desktopcomputer")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(Palette.accent)
|
.foregroundStyle(Palette.accent)
|
||||||
|
|||||||
Reference in New Issue
Block a user