runtime: remove fake companion responses
This commit is contained in:
parent
67df7d1a53
commit
2fb7514daa
|
|
@ -960,7 +960,7 @@ mod tests {
|
|||
.await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let detail: RuntimeHttpWorkerResponse = read_json(response).await;
|
||||
assert_eq!(detail.worker.transcript_len, 2);
|
||||
assert_eq!(detail.worker.transcript_len, 1);
|
||||
|
||||
let response = empty_request(
|
||||
app.clone(),
|
||||
|
|
@ -999,7 +999,7 @@ mod tests {
|
|||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let workers: RuntimeHttpWorkersResponse = read_json(response).await;
|
||||
assert_eq!(workers.workers.len(), 1);
|
||||
assert_eq!(workers.workers[0].transcript_len, 2);
|
||||
assert_eq!(workers.workers[0].transcript_len, 1);
|
||||
|
||||
let response = empty_request(app, Method::GET, "/v1/runtime").await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
|
|
|||
|
|
@ -33,10 +33,6 @@ use tokio::sync::broadcast;
|
|||
|
||||
static NEXT_RUNTIME_SEQUENCE: AtomicU64 = AtomicU64::new(1);
|
||||
|
||||
fn providerless_embedded_response_text() -> &'static str {
|
||||
"Embedded worker-runtime accepted the message. LLM execution is not connected for this worker yet."
|
||||
}
|
||||
|
||||
/// Concrete embedded Runtime domain entity.
|
||||
///
|
||||
/// The default implementation is memory-backed and tools/provider-less by
|
||||
|
|
@ -319,36 +315,10 @@ impl Runtime {
|
|||
};
|
||||
state.push_worker_observation_event(worker_ref.clone(), payload);
|
||||
}
|
||||
let assistant_transcript_sequence = if matches!(role, TranscriptRole::User) {
|
||||
let assistant_text = providerless_embedded_response_text().to_string();
|
||||
let worker = state.worker_mut(worker_ref)?;
|
||||
let assistant_sequence = worker.next_transcript_sequence;
|
||||
worker.next_transcript_sequence += 1;
|
||||
worker.transcript.push(TranscriptEntry {
|
||||
sequence: assistant_sequence,
|
||||
worker_ref: worker_ref.clone(),
|
||||
role: TranscriptRole::Assistant,
|
||||
content: assistant_text.clone(),
|
||||
event_id,
|
||||
});
|
||||
#[cfg(feature = "ws-server")]
|
||||
state.push_worker_observation_event(
|
||||
worker_ref.clone(),
|
||||
protocol::Event::TextDone {
|
||||
text: assistant_text,
|
||||
},
|
||||
);
|
||||
Some(assistant_sequence)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
state.persist_runtime_snapshot()?;
|
||||
state.persist_worker(&worker_ref.worker_id)?;
|
||||
state.persist_event_by_id(event_id)?;
|
||||
state.persist_transcript_entry(&worker_ref.worker_id, transcript_sequence)?;
|
||||
if let Some(sequence) = assistant_transcript_sequence {
|
||||
state.persist_transcript_entry(&worker_ref.worker_id, sequence)?;
|
||||
}
|
||||
|
||||
Ok(WorkerInteractionAck {
|
||||
worker_ref: worker_ref.clone(),
|
||||
|
|
@ -1412,10 +1382,10 @@ mod tests {
|
|||
let projection = runtime
|
||||
.transcript_projection(&detail.worker_ref, TranscriptQuery::new(0, 2))
|
||||
.unwrap();
|
||||
assert_eq!(projection.total_items, 5);
|
||||
assert_eq!(projection.total_items, 3);
|
||||
assert_eq!(projection.items.len(), 2);
|
||||
assert_eq!(projection.items[0].content, "hello");
|
||||
assert_eq!(projection.items[1].role, TranscriptRole::Assistant);
|
||||
assert_eq!(projection.items[1].role, TranscriptRole::System);
|
||||
assert_eq!(projection.next_start, Some(2));
|
||||
|
||||
let err = runtime
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use chrono::Utc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use worker_runtime::catalog::{CapabilityRequest, ProfileSelector};
|
||||
|
||||
use crate::hosts::{
|
||||
DiagnosticSeverity, RuntimeDiagnostic, RuntimeRegistry, WorkerInputKind, WorkerInputRequest,
|
||||
WorkerOperationState, WorkerSpawnAcceptanceRequirement, WorkerSpawnIntent, WorkerSpawnRequest,
|
||||
WorkerSummary,
|
||||
DiagnosticSeverity, RuntimeDiagnostic, RuntimeRegistry, WorkerOperationState,
|
||||
WorkerSpawnAcceptanceRequirement, WorkerSpawnIntent, WorkerSpawnRequest, WorkerSummary,
|
||||
};
|
||||
|
||||
const COMPANION_RUNTIME_ID: &str = "embedded-worker-runtime";
|
||||
const MAX_MESSAGE_CHARS: usize = 8_000;
|
||||
const PROVIDERLESS_RESPONSE: &str =
|
||||
include_str!("../../../resources/prompts/worker/web_companion_providerless.md");
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
|
@ -103,7 +99,6 @@ struct CompanionWorkerState {
|
|||
}
|
||||
|
||||
pub struct CompanionConsole {
|
||||
runtime: Arc<RuntimeRegistry>,
|
||||
worker: Mutex<CompanionWorkerState>,
|
||||
transcript: Mutex<CompanionTranscript>,
|
||||
}
|
||||
|
|
@ -112,7 +107,6 @@ impl CompanionConsole {
|
|||
pub fn new(runtime: Arc<RuntimeRegistry>) -> Self {
|
||||
let initial = spawn_companion_worker(&runtime);
|
||||
Self {
|
||||
runtime,
|
||||
worker: Mutex::new(initial),
|
||||
transcript: Mutex::new(CompanionTranscript::default()),
|
||||
}
|
||||
|
|
@ -125,7 +119,7 @@ impl CompanionConsole {
|
|||
return CompanionStatusResponse {
|
||||
state: CompanionState::Error,
|
||||
worker: None,
|
||||
transport: providerless_transport(),
|
||||
transport: companion_transport(),
|
||||
diagnostics: vec![diagnostic(
|
||||
"companion_state_unavailable",
|
||||
DiagnosticSeverity::Error,
|
||||
|
|
@ -137,7 +131,7 @@ impl CompanionConsole {
|
|||
CompanionStatusResponse {
|
||||
state: worker.state,
|
||||
worker: worker.worker.clone(),
|
||||
transport: providerless_transport(),
|
||||
transport: companion_transport(),
|
||||
diagnostics: worker.diagnostics.clone(),
|
||||
}
|
||||
}
|
||||
|
|
@ -181,125 +175,18 @@ impl CompanionConsole {
|
|||
));
|
||||
}
|
||||
|
||||
let mut transcript = match self.transcript.try_lock() {
|
||||
Ok(transcript) => transcript,
|
||||
Err(std::sync::TryLockError::WouldBlock) => {
|
||||
return self.busy_message_response();
|
||||
}
|
||||
Err(std::sync::TryLockError::Poisoned(_)) => {
|
||||
return self.error_message_response(diagnostic(
|
||||
"companion_transcript_unavailable",
|
||||
DiagnosticSeverity::Error,
|
||||
"Companion transcript is unavailable",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let (worker, mut diagnostics) = match self.current_worker() {
|
||||
Ok((Some(worker), diagnostics)) => (worker, diagnostics),
|
||||
Ok((None, diagnostics)) => {
|
||||
return response_from_locked_transcript(
|
||||
&transcript,
|
||||
CompanionState::Error,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
0,
|
||||
200,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
Err(diagnostic) => {
|
||||
return response_from_locked_transcript(
|
||||
&transcript,
|
||||
CompanionState::Error,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
0,
|
||||
200,
|
||||
vec![diagnostic],
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let user_item = transcript.push("user", content.clone(), "browser_request", "accepted");
|
||||
match self.runtime.send_input(
|
||||
&worker.runtime_id,
|
||||
&worker.worker_id,
|
||||
WorkerInputRequest {
|
||||
kind: WorkerInputKind::User,
|
||||
content,
|
||||
},
|
||||
) {
|
||||
Ok(result) if result.state == WorkerOperationState::Accepted => {
|
||||
diagnostics.extend(result.diagnostics);
|
||||
}
|
||||
Ok(result) => {
|
||||
diagnostics.extend(result.diagnostics);
|
||||
diagnostics.push(diagnostic(
|
||||
"companion_runtime_input_rejected",
|
||||
DiagnosticSeverity::Error,
|
||||
"Embedded Companion Worker rejected the browser message",
|
||||
));
|
||||
return response_from_locked_transcript(
|
||||
&transcript,
|
||||
CompanionState::Error,
|
||||
Some(worker),
|
||||
Some(user_item),
|
||||
None,
|
||||
0,
|
||||
200,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
Err(error) => {
|
||||
diagnostics.push(diagnostic(
|
||||
"companion_runtime_input_failed",
|
||||
DiagnosticSeverity::Error,
|
||||
format!("Embedded Companion Worker input failed: {error:?}"),
|
||||
));
|
||||
return response_from_locked_transcript(
|
||||
&transcript,
|
||||
CompanionState::Error,
|
||||
Some(worker),
|
||||
Some(user_item),
|
||||
None,
|
||||
0,
|
||||
200,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics.push(diagnostic(
|
||||
"companion_providerless_boundary",
|
||||
DiagnosticSeverity::Info,
|
||||
"Real LLM completion is not connected in this MVP; response is the backend provider-less boundary text",
|
||||
));
|
||||
let assistant_item = transcript.push(
|
||||
"assistant",
|
||||
providerless_response_text(),
|
||||
"backend_providerless_boundary",
|
||||
"complete",
|
||||
);
|
||||
response_from_locked_transcript(
|
||||
&transcript,
|
||||
CompanionState::Accepted,
|
||||
Some(worker),
|
||||
Some(user_item),
|
||||
Some(assistant_item),
|
||||
0,
|
||||
200,
|
||||
diagnostics,
|
||||
)
|
||||
self.rejected_message_response(diagnostic(
|
||||
"companion_llm_not_connected",
|
||||
DiagnosticSeverity::Error,
|
||||
"Workspace Companion input is disabled until it is connected to actual Worker/LLM execution",
|
||||
))
|
||||
}
|
||||
|
||||
pub fn cancel(&self, _request: CompanionCancelRequest) -> CompanionMessageResponse {
|
||||
let diagnostics = vec![diagnostic(
|
||||
"companion_cancel_no_active_run",
|
||||
DiagnosticSeverity::Info,
|
||||
"Provider-less Companion Console has no active generation to cancel",
|
||||
"Workspace Companion has no active generation to cancel",
|
||||
)];
|
||||
match self.transcript.lock() {
|
||||
Ok(transcript) => response_from_locked_transcript(
|
||||
|
|
@ -335,19 +222,6 @@ impl CompanionConsole {
|
|||
}
|
||||
}
|
||||
|
||||
fn current_worker(
|
||||
&self,
|
||||
) -> Result<(Option<WorkerSummary>, Vec<RuntimeDiagnostic>), RuntimeDiagnostic> {
|
||||
let worker = self.worker.lock().map_err(|_| {
|
||||
diagnostic(
|
||||
"companion_state_unavailable",
|
||||
DiagnosticSeverity::Error,
|
||||
"Companion state is unavailable",
|
||||
)
|
||||
})?;
|
||||
Ok((worker.worker.clone(), worker.diagnostics.clone()))
|
||||
}
|
||||
|
||||
fn rejected_message_response(&self, diagnostic: RuntimeDiagnostic) -> CompanionMessageResponse {
|
||||
match self.transcript.lock() {
|
||||
Ok(transcript) => response_from_locked_transcript(
|
||||
|
|
@ -378,83 +252,6 @@ impl CompanionConsole {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn busy_message_response(&self) -> CompanionMessageResponse {
|
||||
let diagnostic = diagnostic(
|
||||
"companion_busy",
|
||||
DiagnosticSeverity::Warning,
|
||||
"Companion Console is already processing a message",
|
||||
);
|
||||
match self.transcript.lock() {
|
||||
Ok(transcript) => response_from_locked_transcript(
|
||||
&transcript,
|
||||
CompanionState::Busy,
|
||||
self.status().worker,
|
||||
None,
|
||||
None,
|
||||
0,
|
||||
200,
|
||||
vec![diagnostic],
|
||||
),
|
||||
Err(_) => CompanionMessageResponse {
|
||||
state: CompanionState::Busy,
|
||||
worker: self.status().worker,
|
||||
user_item: None,
|
||||
assistant_item: None,
|
||||
transcript: CompanionTranscriptProjection {
|
||||
state: CompanionState::Busy,
|
||||
start: 0,
|
||||
limit: 200,
|
||||
total_items: 0,
|
||||
next_start: None,
|
||||
items: Vec::new(),
|
||||
diagnostics: vec![diagnostic.clone()],
|
||||
},
|
||||
diagnostics: vec![diagnostic],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn error_message_response(&self, diagnostic: RuntimeDiagnostic) -> CompanionMessageResponse {
|
||||
CompanionMessageResponse {
|
||||
state: CompanionState::Error,
|
||||
worker: self.status().worker,
|
||||
user_item: None,
|
||||
assistant_item: None,
|
||||
transcript: CompanionTranscriptProjection {
|
||||
state: CompanionState::Error,
|
||||
start: 0,
|
||||
limit: 200,
|
||||
total_items: 0,
|
||||
next_start: None,
|
||||
items: Vec::new(),
|
||||
diagnostics: vec![diagnostic.clone()],
|
||||
},
|
||||
diagnostics: vec![diagnostic],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CompanionTranscript {
|
||||
fn push(
|
||||
&mut self,
|
||||
role: impl Into<String>,
|
||||
content: impl Into<String>,
|
||||
source: impl Into<String>,
|
||||
status: impl Into<String>,
|
||||
) -> CompanionTranscriptItem {
|
||||
self.next_sequence = self.next_sequence.saturating_add(1);
|
||||
let item = CompanionTranscriptItem {
|
||||
sequence: self.next_sequence,
|
||||
role: role.into(),
|
||||
content: content.into(),
|
||||
created_at: Utc::now().to_rfc3339(),
|
||||
source: source.into(),
|
||||
status: status.into(),
|
||||
};
|
||||
self.items.push(item.clone());
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_companion_worker(runtime: &RuntimeRegistry) -> CompanionWorkerState {
|
||||
|
|
@ -537,15 +334,11 @@ fn project_transcript(
|
|||
}
|
||||
}
|
||||
|
||||
fn providerless_response_text() -> String {
|
||||
PROVIDERLESS_RESPONSE.trim().to_string()
|
||||
}
|
||||
|
||||
fn providerless_transport() -> CompanionTransportSummary {
|
||||
fn companion_transport() -> CompanionTransportSummary {
|
||||
CompanionTransportSummary {
|
||||
kind: "providerless_backend_internal".to_string(),
|
||||
completion: "synchronous_request_response".to_string(),
|
||||
limitation: "No provider-backed LLM generation is wired in this MVP; browser messages are recorded by a backend-internal tools-less Companion Worker and receive a resource-defined boundary response.".to_string(),
|
||||
kind: "embedded_worker_runtime".to_string(),
|
||||
completion: "not_connected".to_string(),
|
||||
limitation: "Workspace Companion is visible as an embedded Worker, but browser input is disabled until actual Worker/LLM execution is connected.".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +360,7 @@ mod tests {
|
|||
use crate::hosts::{EmbeddedWorkerRuntime, RuntimeRegistry};
|
||||
|
||||
#[test]
|
||||
fn companion_spawns_visible_worker_and_records_providerless_turn() {
|
||||
fn companion_spawns_visible_worker_without_fake_turn() {
|
||||
let registry =
|
||||
RuntimeRegistry::for_workspace(EmbeddedWorkerRuntime::new_memory("local:test"));
|
||||
let registry = Arc::new(registry);
|
||||
|
|
@ -591,22 +384,19 @@ mod tests {
|
|||
let response = companion.send_message(CompanionMessageRequest {
|
||||
content: "hello".to_string(),
|
||||
});
|
||||
assert_eq!(response.state, CompanionState::Accepted);
|
||||
assert_eq!(response.transcript.items.len(), 2);
|
||||
assert_eq!(response.transcript.items[0].role, "user");
|
||||
assert_eq!(response.transcript.items[1].role, "assistant");
|
||||
assert_eq!(response.state, CompanionState::Rejected);
|
||||
assert!(response.transcript.items.is_empty());
|
||||
assert!(
|
||||
response.transcript.items[1]
|
||||
.content
|
||||
.contains("provider-less")
|
||||
response
|
||||
.diagnostics
|
||||
.iter()
|
||||
.any(|diagnostic| diagnostic.code == "companion_llm_not_connected")
|
||||
);
|
||||
|
||||
let runtime_transcript = registry
|
||||
.transcript(COMPANION_RUNTIME_ID, &worker.worker_id, 0, 10)
|
||||
.unwrap();
|
||||
assert_eq!(runtime_transcript.items.len(), 2);
|
||||
assert_eq!(runtime_transcript.items[0].role, "user");
|
||||
assert_eq!(runtime_transcript.items[1].role, "assistant");
|
||||
assert!(runtime_transcript.items.is_empty());
|
||||
|
||||
let browser_payload = serde_json::to_string(&(status, response)).unwrap();
|
||||
for forbidden in [
|
||||
|
|
|
|||
|
|
@ -957,7 +957,7 @@ impl EmbeddedWorkerRuntime {
|
|||
display_hint: "backend-internal worker-runtime Worker".to_string(),
|
||||
},
|
||||
capabilities: WorkerCapabilitySummary {
|
||||
can_accept_input: true,
|
||||
can_accept_input: false,
|
||||
can_stop: false,
|
||||
can_spawn_followup: false,
|
||||
},
|
||||
|
|
@ -989,7 +989,7 @@ impl EmbeddedWorkerRuntime {
|
|||
display_hint: "backend-internal worker-runtime Worker".to_string(),
|
||||
},
|
||||
capabilities: WorkerCapabilitySummary {
|
||||
can_accept_input: true,
|
||||
can_accept_input: false,
|
||||
can_stop: false,
|
||||
can_spawn_followup: false,
|
||||
},
|
||||
|
|
@ -1255,40 +1255,17 @@ impl WorkspaceWorkerRuntime for EmbeddedWorkerRuntime {
|
|||
))
|
||||
}
|
||||
|
||||
fn send_input(&self, worker_id: &str, request: WorkerInputRequest) -> WorkerInputResult {
|
||||
let Some(worker_ref) = self.worker_ref(worker_id) else {
|
||||
return embedded_input_rejected(
|
||||
&self.runtime_id,
|
||||
worker_id,
|
||||
diagnostic(
|
||||
"embedded_worker_id_invalid",
|
||||
DiagnosticSeverity::Warning,
|
||||
"Worker id was empty and cannot be resolved".to_string(),
|
||||
),
|
||||
);
|
||||
};
|
||||
let input = EmbeddedWorkerInput {
|
||||
kind: match request.kind {
|
||||
WorkerInputKind::User => EmbeddedWorkerInputKind::User,
|
||||
WorkerInputKind::System => EmbeddedWorkerInputKind::System,
|
||||
},
|
||||
content: request.content,
|
||||
};
|
||||
match self.runtime.send_input(&worker_ref, input) {
|
||||
Ok(ack) => WorkerInputResult {
|
||||
state: WorkerOperationState::Accepted,
|
||||
runtime_id: self.runtime_id.clone(),
|
||||
worker_id: worker_id.to_string(),
|
||||
transcript_sequence: Some(ack.transcript_sequence),
|
||||
event_id: Some(ack.event_id),
|
||||
diagnostics: Vec::new(),
|
||||
},
|
||||
Err(err) => embedded_input_rejected(
|
||||
&self.runtime_id,
|
||||
worker_id,
|
||||
embedded_runtime_diagnostic(&err),
|
||||
fn send_input(&self, worker_id: &str, _request: WorkerInputRequest) -> WorkerInputResult {
|
||||
embedded_input_rejected(
|
||||
&self.runtime_id,
|
||||
worker_id,
|
||||
diagnostic(
|
||||
"embedded_worker_llm_not_connected",
|
||||
DiagnosticSeverity::Error,
|
||||
"Embedded Worker input is disabled until actual Worker/LLM execution is connected"
|
||||
.to_string(),
|
||||
),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn transcript(
|
||||
|
|
@ -1878,7 +1855,7 @@ fn embedded_runtime_capabilities(limit: usize, available: bool) -> RuntimeCapabi
|
|||
can_get_worker: available,
|
||||
can_spawn_worker: available,
|
||||
can_stop_worker: false,
|
||||
can_accept_input: available,
|
||||
can_accept_input: false,
|
||||
has_workspace_fs: false,
|
||||
has_shell: false,
|
||||
has_git: false,
|
||||
|
|
@ -2611,7 +2588,7 @@ mod tests {
|
|||
);
|
||||
assert_eq!(embedded_summary.source.status, RuntimeSourceStatus::Active);
|
||||
assert!(embedded_summary.capabilities.can_spawn_worker);
|
||||
assert!(embedded_summary.capabilities.can_accept_input);
|
||||
assert!(!embedded_summary.capabilities.can_accept_input);
|
||||
|
||||
let spawned = registry
|
||||
.spawn_worker(
|
||||
|
|
@ -2644,7 +2621,7 @@ mod tests {
|
|||
assert_eq!(worker.workspace.identity, "runtime_registry_worker");
|
||||
assert_eq!(worker.implementation.kind, "embedded_worker_runtime");
|
||||
assert_eq!(worker.profile.as_deref(), Some("builtin:coder"));
|
||||
assert!(worker.capabilities.can_accept_input);
|
||||
assert!(!worker.capabilities.can_accept_input);
|
||||
|
||||
let input = registry
|
||||
.send_input(
|
||||
|
|
@ -2656,24 +2633,21 @@ mod tests {
|
|||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(input.state, WorkerOperationState::Accepted);
|
||||
assert_eq!(input.state, WorkerOperationState::Rejected);
|
||||
assert_eq!(input.runtime_id, EMBEDDED_RUNTIME_ID);
|
||||
assert_eq!(input.worker_id, worker.worker_id);
|
||||
assert_eq!(input.transcript_sequence, Some(1));
|
||||
assert!(
|
||||
input
|
||||
.diagnostics
|
||||
.iter()
|
||||
.any(|diagnostic| diagnostic.code == "embedded_worker_llm_not_connected")
|
||||
);
|
||||
|
||||
let transcript = registry
|
||||
.transcript(EMBEDDED_RUNTIME_ID, &worker.worker_id, 0, 10)
|
||||
.unwrap();
|
||||
assert_eq!(transcript.state, WorkerOperationState::Accepted);
|
||||
assert_eq!(transcript.items.len(), 2);
|
||||
assert_eq!(transcript.items[0].role, "user");
|
||||
assert_eq!(transcript.items[0].content, "hello embedded runtime");
|
||||
assert_eq!(transcript.items[1].role, "assistant");
|
||||
assert!(
|
||||
transcript.items[1]
|
||||
.content
|
||||
.contains("LLM execution is not connected")
|
||||
);
|
||||
assert!(transcript.items.is_empty());
|
||||
|
||||
let json = serde_json::to_string(&(embedded_summary, worker, transcript)).unwrap();
|
||||
for forbidden in [
|
||||
|
|
|
|||
|
|
@ -327,16 +327,16 @@ async fn get_workspace(State(api): State<WorkspaceApi>) -> ApiResult<Json<Worksp
|
|||
extension_points: ExtensionPoints {
|
||||
store: "sqlite".to_string(),
|
||||
event_stream: ExtensionPointState {
|
||||
status: "reserved".to_string(),
|
||||
note: "No browser-to-Worker socket path is exposed in this bootstrap; any future stream must be a Workspace server proxy that resolves Worker identity and enforces method allow/block boundaries.".to_string(),
|
||||
status: "backend_proxy".to_string(),
|
||||
note: "Worker observation streams are exposed only through the Workspace server proxy keyed by runtime_id + worker_id; browser clients never receive raw Runtime endpoints or socket paths.".to_string(),
|
||||
},
|
||||
host_worker_bridge: ExtensionPointState {
|
||||
status: "read_only_local".to_string(),
|
||||
note: "Local Hosts and Workers are exposed as a read-only bridge over existing Worker metadata; no direct Worker socket, scheduling, or lifecycle control is implemented.".to_string(),
|
||||
status: "runtime_registry".to_string(),
|
||||
note: "Hosts and Workers are projected from the Workspace RuntimeRegistry; raw Runtime endpoints, sockets, and local metadata paths are not exposed.".to_string(),
|
||||
},
|
||||
companion_console: ExtensionPointState {
|
||||
status: "providerless_mvp".to_string(),
|
||||
note: "Backend-internal tools-less Companion Worker is available through Workspace API status/transcript/message endpoints; v0 records browser messages and returns a resource-defined provider-less response instead of direct LLM generation.".to_string(),
|
||||
status: "not_connected".to_string(),
|
||||
note: "Workspace Companion is visible as an embedded Worker, but browser input is disabled until actual Worker/LLM execution is connected.".to_string(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
|
@ -1051,7 +1051,7 @@ mod tests {
|
|||
assert_eq!(workspace["record_authority"], "local_yoi_project_records");
|
||||
assert_eq!(
|
||||
workspace["extension_points"]["host_worker_bridge"]["status"],
|
||||
"read_only_local"
|
||||
"runtime_registry"
|
||||
);
|
||||
|
||||
let tickets = get_json(app.clone(), "/api/tickets").await;
|
||||
|
|
@ -1141,7 +1141,7 @@ mod tests {
|
|||
assert_eq!(companion_status["worker"]["role"], "workspace_companion");
|
||||
assert_eq!(
|
||||
companion_status["transport"]["kind"],
|
||||
"providerless_backend_internal"
|
||||
"embedded_worker_runtime"
|
||||
);
|
||||
assert!(!companion_status.to_string().contains("/workspace/demo"));
|
||||
|
||||
|
|
@ -1151,23 +1151,24 @@ mod tests {
|
|||
json!({ "content": "hello companion" }),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(companion_message["state"], "accepted");
|
||||
assert_eq!(companion_message["transcript"]["items"][0]["role"], "user");
|
||||
assert_eq!(
|
||||
companion_message["transcript"]["items"][1]["role"],
|
||||
"assistant"
|
||||
assert_eq!(companion_message["state"], "rejected");
|
||||
assert!(
|
||||
companion_message["transcript"]["items"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.is_empty()
|
||||
);
|
||||
assert!(
|
||||
companion_message["transcript"]["items"][1]["content"]
|
||||
.as_str()
|
||||
companion_message["diagnostics"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.contains("provider-less")
|
||||
.iter()
|
||||
.any(|diagnostic| diagnostic["code"] == "companion_llm_not_connected")
|
||||
);
|
||||
assert!(!companion_message.to_string().contains("/workspace/demo"));
|
||||
|
||||
let companion_transcript = get_json(app.clone(), "/api/companion/transcript").await;
|
||||
assert_eq!(companion_transcript["total_items"], 2);
|
||||
assert_eq!(companion_transcript["items"][1]["role"], "assistant");
|
||||
assert_eq!(companion_transcript["total_items"], 0);
|
||||
|
||||
let host_workers = get_json(app.clone(), &format!("/api/hosts/{host_id}/workers")).await;
|
||||
assert!(
|
||||
|
|
@ -1328,10 +1329,16 @@ mod tests {
|
|||
}),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(accepted["state"], "accepted");
|
||||
assert_eq!(accepted["state"], "rejected");
|
||||
assert_eq!(accepted["runtime_id"], "embedded-worker-runtime");
|
||||
assert_eq!(accepted["worker_id"], worker_id);
|
||||
assert_eq!(accepted["transcript_sequence"], 1);
|
||||
assert!(
|
||||
accepted["diagnostics"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|diagnostic| diagnostic["code"] == "embedded_worker_llm_not_connected")
|
||||
);
|
||||
|
||||
let transcript = get_json(
|
||||
app.clone(),
|
||||
|
|
@ -1339,11 +1346,7 @@ mod tests {
|
|||
)
|
||||
.await;
|
||||
assert_eq!(transcript["state"], "accepted");
|
||||
assert_eq!(transcript["items"][0]["role"], "user");
|
||||
assert_eq!(
|
||||
transcript["items"][0]["content"],
|
||||
"hello from browser-facing api"
|
||||
);
|
||||
assert!(transcript["items"].as_array().unwrap().is_empty());
|
||||
|
||||
let wrong_runtime = app
|
||||
.clone()
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
You are connected to the Yoi Workspace Web Console MVP provider-less boundary.
|
||||
|
||||
I received your browser message through the backend-internal Companion Worker, but this MVP does not yet run a provider-backed LLM completion from the workspace server. The transcript/status/send path is active, tools-less, and scoped to conversation projection only. A later integration can replace this resource-defined boundary response with real Worker engine output without giving the browser runtime credentials, sockets, session paths, or filesystem authority.
|
||||
Loading…
Reference in New Issue
Block a user