mirror of
https://github.com/block/goose.git
synced 2026-07-09 16:09:22 +00:00
Remove MCP sampling support (#10087)
Some checks are pending
Canary / Prepare Version (push) Waiting to run
Canary / build-cli (push) Blocked by required conditions
Canary / Upload Install Script (push) Blocked by required conditions
Canary / bundle-desktop (push) Blocked by required conditions
Canary / bundle-desktop-intel (push) Blocked by required conditions
Canary / bundle-desktop-linux (push) Blocked by required conditions
Canary / bundle-desktop-windows (push) Blocked by required conditions
Canary / bundle-desktop-windows-cuda (push) Blocked by required conditions
Canary / Release (push) Blocked by required conditions
Cargo Deny / deny (push) Waiting to run
Unused Dependencies / machete (push) Waiting to run
CI / changes (push) Waiting to run
CI / Check Rust Code Format (push) Blocked by required conditions
CI / Build and Test Rust Project (push) Blocked by required conditions
CI / Build Rust Project on Windows (push) Waiting to run
CI / Check MSRV (push) Blocked by required conditions
CI / Lint Rust Code (push) Blocked by required conditions
CI / Check Generated Schemas are Up-to-Date (push) Blocked by required conditions
CI / Test and Lint Electron Desktop App (push) Blocked by required conditions
Deploy Documentation / deploy (push) Waiting to run
Create Minor Release PR / check-version-bump-pr (push) Waiting to run
Create Minor Release PR / release (push) Blocked by required conditions
Live Provider Tests / check-fork (push) Waiting to run
Live Provider Tests / changes (push) Blocked by required conditions
Live Provider Tests / Build Binary (push) Blocked by required conditions
Live Provider Tests / Smoke Tests (push) Blocked by required conditions
Live Provider Tests / Smoke Tests (Code Execution) (push) Blocked by required conditions
Live Provider Tests / Compaction Tests (push) Blocked by required conditions
Live Provider Tests / goose server HTTP integration tests (push) Blocked by required conditions
Publish Ask AI Bot Docker Image / docker (push) Waiting to run
Publish Docker Image / docker (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Some checks are pending
Canary / Prepare Version (push) Waiting to run
Canary / build-cli (push) Blocked by required conditions
Canary / Upload Install Script (push) Blocked by required conditions
Canary / bundle-desktop (push) Blocked by required conditions
Canary / bundle-desktop-intel (push) Blocked by required conditions
Canary / bundle-desktop-linux (push) Blocked by required conditions
Canary / bundle-desktop-windows (push) Blocked by required conditions
Canary / bundle-desktop-windows-cuda (push) Blocked by required conditions
Canary / Release (push) Blocked by required conditions
Cargo Deny / deny (push) Waiting to run
Unused Dependencies / machete (push) Waiting to run
CI / changes (push) Waiting to run
CI / Check Rust Code Format (push) Blocked by required conditions
CI / Build and Test Rust Project (push) Blocked by required conditions
CI / Build Rust Project on Windows (push) Waiting to run
CI / Check MSRV (push) Blocked by required conditions
CI / Lint Rust Code (push) Blocked by required conditions
CI / Check Generated Schemas are Up-to-Date (push) Blocked by required conditions
CI / Test and Lint Electron Desktop App (push) Blocked by required conditions
Deploy Documentation / deploy (push) Waiting to run
Create Minor Release PR / check-version-bump-pr (push) Waiting to run
Create Minor Release PR / release (push) Blocked by required conditions
Live Provider Tests / check-fork (push) Waiting to run
Live Provider Tests / changes (push) Blocked by required conditions
Live Provider Tests / Build Binary (push) Blocked by required conditions
Live Provider Tests / Smoke Tests (push) Blocked by required conditions
Live Provider Tests / Smoke Tests (Code Execution) (push) Blocked by required conditions
Live Provider Tests / Compaction Tests (push) Blocked by required conditions
Live Provider Tests / goose server HTTP integration tests (push) Blocked by required conditions
Publish Ask AI Bot Docker Image / docker (push) Waiting to run
Publish Docker Image / docker (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Co-authored-by: Douwe M Osinga <douwe@sidewalklabs.com> Co-authored-by: Lifei Zhou <lifei@squareup.com>
This commit is contained in:
parent
c8971fe5fb
commit
66ce9a6beb
25 changed files with 144 additions and 345 deletions
|
|
@ -8,7 +8,6 @@ pub mod prompts;
|
|||
pub mod recipe;
|
||||
pub mod recipe_utils;
|
||||
pub mod reply;
|
||||
pub mod sampling;
|
||||
pub mod schedule;
|
||||
pub mod session;
|
||||
pub mod session_events;
|
||||
|
|
@ -35,6 +34,5 @@ pub fn configure(state: Arc<crate::state::AppState>, secret_key: String) -> Rout
|
|||
.merge(telemetry::routes(state.clone()))
|
||||
.merge(mcp_app_proxy::routes(secret_key))
|
||||
.merge(session_events::routes(state.clone()))
|
||||
.merge(sampling::routes(state.clone()))
|
||||
.merge(dictation::routes(state.clone()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
use axum::{
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
routing::post,
|
||||
Json, Router,
|
||||
};
|
||||
use goose::conversation::message::Message;
|
||||
use rmcp::model::{
|
||||
CreateMessageRequestParams, CreateMessageResult, Role, SamplingContent, SamplingMessage,
|
||||
SamplingMessageContent,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
pub fn routes(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
.route(
|
||||
"/sessions/{session_id}/sampling/message",
|
||||
post(create_message),
|
||||
)
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
async fn create_message(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Path(session_id): Path<String>,
|
||||
Json(request): Json<CreateMessageRequestParams>,
|
||||
) -> Result<Json<CreateMessageResult>, StatusCode> {
|
||||
let agent = state.get_agent_for_route(session_id.clone()).await?;
|
||||
|
||||
let provider = agent.provider().await.map_err(|e| {
|
||||
tracing::error!("Failed to get provider: {}", e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
|
||||
let messages: Vec<Message> = request
|
||||
.messages
|
||||
.iter()
|
||||
.map(|msg| {
|
||||
let base = match msg.role {
|
||||
Role::User => Message::user(),
|
||||
Role::Assistant => Message::assistant(),
|
||||
};
|
||||
content_to_message(base, &msg.content)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let system = request
|
||||
.system_prompt
|
||||
.as_deref()
|
||||
.unwrap_or("You are a helpful AI assistant.");
|
||||
|
||||
let model_config = agent
|
||||
.model_config_for_session(&session_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Failed to resolve model config: {}", e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
let (response, usage) = goose::session_context::with_session_id(
|
||||
Some(session_id.clone()),
|
||||
provider.complete(&model_config, system, &messages, &[]),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Sampling completion failed: {}", e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
|
||||
let text = response.as_concat_text();
|
||||
|
||||
Ok(Json(
|
||||
CreateMessageResult::new(
|
||||
SamplingMessage::new(Role::Assistant, SamplingMessageContent::text(&text)),
|
||||
usage.model,
|
||||
)
|
||||
.with_stop_reason(CreateMessageResult::STOP_REASON_END_TURN),
|
||||
))
|
||||
}
|
||||
|
||||
fn content_to_message(base: Message, content: &SamplingContent<SamplingMessageContent>) -> Message {
|
||||
let items = match content {
|
||||
SamplingContent::Single(item) => vec![item],
|
||||
SamplingContent::Multiple(items) => items.iter().collect(),
|
||||
};
|
||||
|
||||
let mut msg = base;
|
||||
for item in items {
|
||||
msg = match item {
|
||||
SamplingMessageContent::Text(text) => msg.with_text(&text.text),
|
||||
SamplingMessageContent::Image(image) => msg.with_image(&image.data, &image.mime_type),
|
||||
_ => msg,
|
||||
};
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ use tracing::warn;
|
|||
use super::app::GooseApp;
|
||||
|
||||
static CLOCK_HTML: &str = include_str!("../goose_apps/clock.html");
|
||||
static CHAT_HTML: &str = include_str!("../goose_apps/chat.html");
|
||||
const APPS_EXTENSION_NAME: &str = "apps";
|
||||
|
||||
pub struct McpAppCache {
|
||||
|
|
@ -25,12 +24,10 @@ impl McpAppCache {
|
|||
}
|
||||
|
||||
fn ensure_default_apps(&self) {
|
||||
for (uri, html) in [("apps://clock", CLOCK_HTML), ("apps://chat", CHAT_HTML)] {
|
||||
if self.get_app(APPS_EXTENSION_NAME, uri).is_none() {
|
||||
if let Ok(mut app) = GooseApp::from_html(html) {
|
||||
app.mcp_servers = vec![APPS_EXTENSION_NAME.to_string()];
|
||||
let _ = self.store_app(&app);
|
||||
}
|
||||
if self.get_app(APPS_EXTENSION_NAME, "apps://clock").is_none() {
|
||||
if let Ok(mut app) = GooseApp::from_html(CLOCK_HTML) {
|
||||
app.mcp_servers = vec![APPS_EXTENSION_NAME.to_string()];
|
||||
let _ = self.store_app(&app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Chat</title>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://goose.ai/schema",
|
||||
"@type": "GooseApp",
|
||||
"name": "chat",
|
||||
"description": "Simple Chat UI",
|
||||
"width": 400,
|
||||
"height": 500,
|
||||
"resizable": true
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body { height: 100%; font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||
body { display: flex; flex-direction: column; background: #fff; }
|
||||
|
||||
.messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.message {
|
||||
max-width: 80%;
|
||||
padding: 10px 14px;
|
||||
border-radius: 16px;
|
||||
line-height: 1.4;
|
||||
font-size: 14px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
align-self: flex-end;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
align-self: flex-start;
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.message.loading {
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
#messageInput {
|
||||
flex: 1;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#messageInput:focus { border-color: #999; }
|
||||
|
||||
#sendBtn {
|
||||
padding: 10px 20px;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#sendBtn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="messages" id="messages"></div>
|
||||
<div class="input-area">
|
||||
<input type="text" id="messageInput" placeholder="Type a message..." />
|
||||
<button id="sendBtn">Send</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const messagesEl = document.getElementById('messages');
|
||||
const inputEl = document.getElementById('messageInput');
|
||||
const sendBtn = document.getElementById('sendBtn');
|
||||
const conversationHistory = [];
|
||||
const pendingRequests = new Map();
|
||||
let requestId = 0;
|
||||
|
||||
function addMessage(role, text, isLoading = false) {
|
||||
const div = document.createElement('div');
|
||||
div.className = `message ${role}${isLoading ? ' loading' : ''}`;
|
||||
div.textContent = text;
|
||||
messagesEl.appendChild(div);
|
||||
messagesEl.scrollTop = messagesEl.scrollHeight;
|
||||
return div;
|
||||
}
|
||||
|
||||
function request(method, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = ++requestId;
|
||||
pendingRequests.set(id, { resolve, reject });
|
||||
window.parent.postMessage({ jsonrpc: '2.0', id, method, params }, '*');
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
const data = event.data;
|
||||
if (!data || typeof data !== 'object') return;
|
||||
|
||||
if ('id' in data && pendingRequests.has(data.id)) {
|
||||
const { resolve, reject } = pendingRequests.get(data.id);
|
||||
pendingRequests.delete(data.id);
|
||||
if (data.error) {
|
||||
reject(new Error(data.error.message || 'Unknown error'));
|
||||
} else {
|
||||
resolve(data.result);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
request('ui/initialize', {}).then(() => {
|
||||
window.parent.postMessage({ jsonrpc: '2.0', method: 'ui/notifications/initialized', params: {} }, '*');
|
||||
});
|
||||
|
||||
async function sendMessage() {
|
||||
const text = inputEl.value.trim();
|
||||
if (!text) return;
|
||||
|
||||
inputEl.value = '';
|
||||
sendBtn.disabled = true;
|
||||
|
||||
addMessage('user', text);
|
||||
conversationHistory.push({ role: 'user', content: { type: 'text', text } });
|
||||
|
||||
const loadingEl = addMessage('assistant', 'Thinking...', true);
|
||||
|
||||
try {
|
||||
const response = await request('sampling/createMessage', {
|
||||
messages: conversationHistory,
|
||||
systemPrompt: 'You are a helpful assistant. Keep responses concise.',
|
||||
maxTokens: 1000
|
||||
});
|
||||
|
||||
const responseText = response.content.text;
|
||||
conversationHistory.push({ role: 'assistant', content: { type: 'text', text: responseText } });
|
||||
|
||||
loadingEl.textContent = responseText;
|
||||
loadingEl.classList.remove('loading');
|
||||
} catch (err) {
|
||||
loadingEl.textContent = 'Error: ' + err.message;
|
||||
loadingEl.classList.remove('loading');
|
||||
}
|
||||
|
||||
sendBtn.disabled = false;
|
||||
inputEl.focus();
|
||||
}
|
||||
|
||||
sendBtn.addEventListener('click', sendMessage);
|
||||
inputEl.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') sendMessage();
|
||||
});
|
||||
|
||||
inputEl.focus();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -51,8 +51,6 @@ import {
|
|||
McpAppToolInputPartial,
|
||||
DimensionLayout,
|
||||
OnDisplayModeChange,
|
||||
SamplingCreateMessageParams,
|
||||
SamplingCreateMessageResponse,
|
||||
} from './types';
|
||||
import {
|
||||
useDisplayMode,
|
||||
|
|
@ -676,13 +674,6 @@ export default function McpAppRenderer({
|
|||
|
||||
const [containerWidth, setContainerWidth] = useState<number>(0);
|
||||
const [containerHeight, setContainerHeight] = useState<number>(0);
|
||||
const [apiHost, setApiHost] = useState<string | null>(null);
|
||||
const [secretKey, setSecretKey] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
window.electron.getGoosedHostPort().then(setApiHost);
|
||||
window.electron.getSecretKey().then(setSecretKey);
|
||||
}, []);
|
||||
|
||||
// Fetch the resource from the extension to get HTML and metadata (CSP, permissions, etc.).
|
||||
// If cachedHtml is provided we show it immediately; the fetch updates metadata and
|
||||
|
|
@ -933,38 +924,12 @@ export default function McpAppRenderer({
|
|||
|
||||
const handleFallbackRequest = useCallback(
|
||||
async (request: JSONRPCRequest, _extra: RequestHandlerExtra) => {
|
||||
if (request.method === 'sampling/createMessage') {
|
||||
if (!sessionId || !apiHost || !secretKey) {
|
||||
throw new Error('Session not initialized for sampling request');
|
||||
}
|
||||
const { messages, systemPrompt, maxTokens } =
|
||||
request.params as unknown as SamplingCreateMessageParams;
|
||||
const response = await fetch(`${apiHost}/sessions/${sessionId}/sampling/message`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Key': secretKey,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: messages.map((m) => ({
|
||||
role: m.role,
|
||||
content: m.content,
|
||||
})),
|
||||
systemPrompt,
|
||||
maxTokens,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Sampling request failed: ${response.statusText}`);
|
||||
}
|
||||
return (await response.json()) as SamplingCreateMessageResponse;
|
||||
}
|
||||
return {
|
||||
status: 'error' as const,
|
||||
message: `Unhandled JSON-RPC method: ${request.method ?? '<unknown>'}`,
|
||||
};
|
||||
},
|
||||
[sessionId, apiHost, secretKey]
|
||||
[]
|
||||
);
|
||||
|
||||
const handleError = useCallback((err: Error) => {
|
||||
|
|
|
|||
|
|
@ -41,21 +41,3 @@ export type McpAppToolCancelled = McpUiToolCancelledNotification['params'];
|
|||
* host-side controls or app-initiated `ui/request-display-mode` changes.
|
||||
*/
|
||||
export type OnDisplayModeChange = (mode: GooseDisplayMode) => void;
|
||||
|
||||
export type SamplingMessage = {
|
||||
role: 'user' | 'assistant';
|
||||
content: { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };
|
||||
};
|
||||
|
||||
export type SamplingCreateMessageParams = {
|
||||
messages: SamplingMessage[];
|
||||
systemPrompt?: string;
|
||||
maxTokens?: number;
|
||||
};
|
||||
|
||||
export type SamplingCreateMessageResponse = {
|
||||
model: string;
|
||||
stopReason: string;
|
||||
role: 'assistant';
|
||||
content: { type: 'text'; text: string };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { MainPanelLayout } from '../Layout/MainPanelLayout';
|
||||
import { Button } from '../ui/button';
|
||||
import { Download, Play, Upload } from 'lucide-react';
|
||||
import { AlertTriangle, Download, Play, Upload } from 'lucide-react';
|
||||
import type { GooseApp } from '../../types/apps';
|
||||
import { exportMcpApp, importMcpApp, listMcpApps } from '../../acp/mcp-apps';
|
||||
import { useChatContext } from '../../contexts/ChatContext';
|
||||
import { formatAppName } from '../../utils/conversionUtils';
|
||||
import { errorMessage } from '../../utils/conversionUtils';
|
||||
import { isRetiredGooseChatApp } from '../../utils/retiredApps';
|
||||
import { defineMessages, useIntl } from '../../i18n';
|
||||
|
||||
const i18n = defineMessages({
|
||||
|
|
@ -52,6 +53,14 @@ const i18n = defineMessages({
|
|||
id: 'appsView.launch',
|
||||
defaultMessage: 'Launch',
|
||||
},
|
||||
retiredChatApp: {
|
||||
id: 'appsView.retiredChatApp',
|
||||
defaultMessage: 'Chat app retired',
|
||||
},
|
||||
retiredChatAppDetail: {
|
||||
id: 'appsView.retiredChatAppDetail',
|
||||
defaultMessage: 'We removed this feature because MCP sampling is no longer supported.',
|
||||
},
|
||||
});
|
||||
|
||||
const GridLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
|
|
@ -272,11 +281,25 @@ export default function AppsView() {
|
|||
<GridLayout>
|
||||
{apps.map((app) => {
|
||||
const isCustomApp = app.mcpServers?.includes('apps') ?? false;
|
||||
const retiredChatApp = isRetiredGooseChatApp(app);
|
||||
return (
|
||||
<div
|
||||
key={`${app.uri}-${app.mcpServers?.join(',')}`}
|
||||
className="flex flex-col p-4 border rounded-lg hover:border-border-primary transition-colors"
|
||||
>
|
||||
{retiredChatApp && (
|
||||
<div className="mb-3 flex items-start gap-2 rounded border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100">
|
||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
|
||||
<div>
|
||||
<div className="font-medium">
|
||||
{intl.formatMessage(i18n.retiredChatApp)}
|
||||
</div>
|
||||
<p className="mt-1 text-xs leading-5">
|
||||
{intl.formatMessage(i18n.retiredChatAppDetail)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1 mb-4">
|
||||
<h3 className="font-medium text-text-primary mb-2">
|
||||
{formatAppName(app.name)}
|
||||
|
|
@ -297,6 +320,7 @@ export default function AppsView() {
|
|||
variant="default"
|
||||
size="sm"
|
||||
onClick={() => handleLaunchApp(app)}
|
||||
disabled={retiredChatApp}
|
||||
className="flex items-center gap-2 flex-1"
|
||||
>
|
||||
<Play className="h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Erneut versuchen"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Apps"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@
|
|||
"appsView.noAppsTitle": {
|
||||
"defaultMessage": "No apps available"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.retry": {
|
||||
"defaultMessage": "Retry"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Reintentar"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Apps"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Réessayer"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Applications"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "पुनः प्रयास करें"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "ऐप्स"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Coba lagi"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Aplikasi"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Riprova"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "App"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "再試行"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "アプリ"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "다시 시도"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "앱"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Cuba semula"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Apl"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Tentar novamente"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Aplicações"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Повторить"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Приложения"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Yeniden dene"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Uygulamalar"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "Thử lại"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "Ứng dụng"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "重试"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "应用"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@
|
|||
"appsView.retry": {
|
||||
"defaultMessage": "重試"
|
||||
},
|
||||
"appsView.retiredChatApp": {
|
||||
"defaultMessage": "Chat app retired"
|
||||
},
|
||||
"appsView.retiredChatAppDetail": {
|
||||
"defaultMessage": "We removed this feature because MCP sampling is no longer supported."
|
||||
},
|
||||
"appsView.title": {
|
||||
"defaultMessage": "應用程式"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import log from './utils/logger';
|
|||
import { ensureWinShims } from './utils/winShims';
|
||||
import { addRecentDir, loadRecentDirs } from './utils/recentDirs';
|
||||
import { formatAppName, errorMessage, formatErrorForLogging } from './utils/conversionUtils';
|
||||
import { isRetiredGooseChatApp } from './utils/retiredApps';
|
||||
import type { Settings, SettingKey } from './utils/settings';
|
||||
import { defaultSettings, getKeyboardShortcuts } from './utils/settings';
|
||||
import * as crypto from 'crypto';
|
||||
|
|
@ -2877,6 +2878,10 @@ async function appMain() {
|
|||
|
||||
ipcMain.handle('launch-app', async (event, gooseApp: GooseApp) => {
|
||||
try {
|
||||
if (isRetiredGooseChatApp(gooseApp)) {
|
||||
throw new Error('This built-in Chat app is no longer supported.');
|
||||
}
|
||||
|
||||
const launchingWindow = BrowserWindow.fromWebContents(event.sender);
|
||||
if (!launchingWindow) {
|
||||
throw new Error('Could not find launching window');
|
||||
|
|
|
|||
13
ui/desktop/src/utils/retiredApps.ts
Normal file
13
ui/desktop/src/utils/retiredApps.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import type { GooseApp } from '../types/apps';
|
||||
|
||||
export function isRetiredGooseChatApp(app: GooseApp) {
|
||||
return (
|
||||
app.mcpServers?.includes('apps') &&
|
||||
app.uri === 'ui://apps/chat' &&
|
||||
app.name === 'chat' &&
|
||||
app.description === 'Simple Chat UI' &&
|
||||
app.width === 400 &&
|
||||
app.height === 500 &&
|
||||
app.resizable === true
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue