@kirosnn/mosaic 0.71.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -5
- package/package.json +4 -2
- package/src/agent/Agent.ts +353 -131
- package/src/agent/context.ts +4 -4
- package/src/agent/prompts/systemPrompt.ts +15 -6
- package/src/agent/prompts/toolsPrompt.ts +136 -10
- package/src/agent/provider/anthropic.ts +100 -100
- package/src/agent/provider/google.ts +102 -102
- package/src/agent/provider/mistral.ts +95 -95
- package/src/agent/provider/ollama.ts +77 -60
- package/src/agent/provider/openai.ts +42 -38
- package/src/agent/provider/rateLimit.ts +178 -0
- package/src/agent/provider/xai.ts +99 -99
- package/src/agent/tools/definitions.ts +19 -9
- package/src/agent/tools/executor.ts +95 -85
- package/src/agent/tools/exploreExecutor.ts +8 -10
- package/src/agent/tools/grep.ts +30 -29
- package/src/agent/tools/question.ts +7 -1
- package/src/agent/types.ts +9 -8
- package/src/components/App.tsx +45 -45
- package/src/components/CustomInput.tsx +214 -36
- package/src/components/Main.tsx +552 -339
- package/src/components/Setup.tsx +1 -1
- package/src/components/Welcome.tsx +1 -1
- package/src/components/main/ApprovalPanel.tsx +4 -3
- package/src/components/main/ChatPage.tsx +858 -675
- package/src/components/main/HomePage.tsx +53 -38
- package/src/components/main/QuestionPanel.tsx +52 -7
- package/src/components/main/ThinkingIndicator.tsx +2 -1
- package/src/index.tsx +50 -20
- package/src/mcp/approvalPolicy.ts +156 -0
- package/src/mcp/cli/add.ts +185 -0
- package/src/mcp/cli/doctor.ts +74 -0
- package/src/mcp/cli/index.ts +85 -0
- package/src/mcp/cli/list.ts +50 -0
- package/src/mcp/cli/logs.ts +24 -0
- package/src/mcp/cli/manage.ts +99 -0
- package/src/mcp/cli/show.ts +53 -0
- package/src/mcp/cli/tools.ts +77 -0
- package/src/mcp/config.ts +234 -0
- package/src/mcp/index.ts +80 -0
- package/src/mcp/processManager.ts +304 -0
- package/src/mcp/rateLimiter.ts +50 -0
- package/src/mcp/registry.ts +151 -0
- package/src/mcp/schemaConverter.ts +100 -0
- package/src/mcp/servers/navigation/browser.ts +151 -0
- package/src/mcp/servers/navigation/index.ts +23 -0
- package/src/mcp/servers/navigation/tools.ts +263 -0
- package/src/mcp/servers/navigation/types.ts +17 -0
- package/src/mcp/servers/navigation/utils.ts +20 -0
- package/src/mcp/toolCatalog.ts +182 -0
- package/src/mcp/types.ts +116 -0
- package/src/utils/approvalBridge.ts +17 -5
- package/src/utils/commands/compact.ts +30 -0
- package/src/utils/commands/echo.ts +1 -1
- package/src/utils/commands/index.ts +4 -6
- package/src/utils/commands/new.ts +15 -0
- package/src/utils/commands/types.ts +3 -0
- package/src/utils/config.ts +3 -1
- package/src/utils/diffRendering.tsx +1 -3
- package/src/utils/exploreBridge.ts +10 -0
- package/src/utils/markdown.tsx +220 -122
- package/src/utils/models.ts +31 -9
- package/src/utils/questionBridge.ts +36 -1
- package/src/utils/tokenEstimator.ts +32 -0
- package/src/utils/toolFormatting.ts +317 -7
- package/src/web/app.tsx +72 -72
- package/src/web/components/HomePage.tsx +7 -7
- package/src/web/components/MessageItem.tsx +66 -35
- package/src/web/components/QuestionPanel.tsx +72 -12
- package/src/web/components/Sidebar.tsx +0 -2
- package/src/web/components/ThinkingIndicator.tsx +1 -0
- package/src/web/server.tsx +767 -683
- package/src/utils/commands/redo.ts +0 -74
- package/src/utils/commands/sessions.ts +0 -129
- package/src/utils/commands/undo.ts +0 -75
- package/src/utils/undoRedo.ts +0 -429
- package/src/utils/undoRedoBridge.ts +0 -45
- package/src/utils/undoRedoDb.ts +0 -338
package/src/mcp/types.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export interface McpTransportConfig {
|
|
2
|
+
type: 'stdio';
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface McpServerConfig {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
native?: boolean;
|
|
10
|
+
transport: McpTransportConfig;
|
|
11
|
+
command: string;
|
|
12
|
+
args: string[];
|
|
13
|
+
cwd?: string;
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
autostart: 'startup' | 'on-demand' | 'never';
|
|
16
|
+
timeouts: {
|
|
17
|
+
initialize: number;
|
|
18
|
+
call: number;
|
|
19
|
+
};
|
|
20
|
+
limits: {
|
|
21
|
+
maxCallsPerMinute: number;
|
|
22
|
+
maxPayloadBytes: number;
|
|
23
|
+
};
|
|
24
|
+
logs: {
|
|
25
|
+
persist: boolean;
|
|
26
|
+
path?: string;
|
|
27
|
+
bufferSize: number;
|
|
28
|
+
};
|
|
29
|
+
tools: {
|
|
30
|
+
allow?: string[];
|
|
31
|
+
deny?: string[];
|
|
32
|
+
};
|
|
33
|
+
approval: McpApprovalMode;
|
|
34
|
+
toolApproval?: Record<string, McpApprovalMode>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type McpApprovalMode = 'always' | 'once-per-tool' | 'once-per-server' | 'never';
|
|
38
|
+
|
|
39
|
+
export type McpServerStatus = 'stopped' | 'starting' | 'running' | 'error';
|
|
40
|
+
|
|
41
|
+
export interface McpServerState {
|
|
42
|
+
status: McpServerStatus;
|
|
43
|
+
pid?: number;
|
|
44
|
+
initLatencyMs?: number;
|
|
45
|
+
toolCount: number;
|
|
46
|
+
lastError?: string;
|
|
47
|
+
lastCallAt?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface McpToolInfo {
|
|
51
|
+
serverId: string;
|
|
52
|
+
name: string;
|
|
53
|
+
description: string;
|
|
54
|
+
inputSchema: Record<string, unknown>;
|
|
55
|
+
canonicalId: string;
|
|
56
|
+
safeId: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type McpRiskHint = 'read' | 'write' | 'execute' | 'network' | 'unknown';
|
|
60
|
+
|
|
61
|
+
export type McpApprovalScope = 'toolArgs' | 'tool' | 'server';
|
|
62
|
+
|
|
63
|
+
export interface McpApprovalCacheEntry {
|
|
64
|
+
scope: McpApprovalScope;
|
|
65
|
+
key: string;
|
|
66
|
+
expiresAt: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface McpGlobalConfig {
|
|
70
|
+
servers: McpServerConfig[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function toCanonicalId(serverId: string, toolName: string): string {
|
|
74
|
+
return `mcp:${serverId}:${toolName}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function toSafeId(serverId: string, toolName: string): string {
|
|
78
|
+
return `mcp__${serverId}__${toolName}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function parseSafeId(safeId: string): { serverId: string; toolName: string } | null {
|
|
82
|
+
if (!safeId.startsWith('mcp__')) return null;
|
|
83
|
+
const parts = safeId.slice(5).split('__');
|
|
84
|
+
if (parts.length < 2) return null;
|
|
85
|
+
const toolName = parts.pop()!;
|
|
86
|
+
const serverId = parts.join('__');
|
|
87
|
+
return { serverId, toolName };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function parseCanonicalId(canonicalId: string): { serverId: string; toolName: string } | null {
|
|
91
|
+
if (!canonicalId.startsWith('mcp:')) return null;
|
|
92
|
+
const parts = canonicalId.slice(4).split(':');
|
|
93
|
+
if (parts.length < 2) return null;
|
|
94
|
+
const toolName = parts.pop()!;
|
|
95
|
+
const serverId = parts.join(':');
|
|
96
|
+
return { serverId, toolName };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const NATIVE_SERVER_IDS = new Set(['navigation']);
|
|
100
|
+
|
|
101
|
+
export function isNativeMcpServer(serverId: string): boolean {
|
|
102
|
+
return NATIVE_SERVER_IDS.has(serverId);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function isNativeMcpTool(safeId: string): boolean {
|
|
106
|
+
const parsed = parseSafeId(safeId);
|
|
107
|
+
if (!parsed) return false;
|
|
108
|
+
return NATIVE_SERVER_IDS.has(parsed.serverId);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getNativeMcpToolName(safeId: string): string | null {
|
|
112
|
+
const parsed = parseSafeId(safeId);
|
|
113
|
+
if (!parsed) return null;
|
|
114
|
+
if (!NATIVE_SERVER_IDS.has(parsed.serverId)) return null;
|
|
115
|
+
return parsed.toolName;
|
|
116
|
+
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
export interface ApprovalRequest {
|
|
2
2
|
id: string;
|
|
3
|
-
toolName:
|
|
3
|
+
toolName: string;
|
|
4
4
|
preview: {
|
|
5
5
|
title: string;
|
|
6
6
|
content: string;
|
|
7
7
|
details?: string[];
|
|
8
8
|
};
|
|
9
9
|
args: Record<string, unknown>;
|
|
10
|
+
mcpMeta?: {
|
|
11
|
+
serverId: string;
|
|
12
|
+
serverName: string;
|
|
13
|
+
canonicalId: string;
|
|
14
|
+
riskHint: string;
|
|
15
|
+
payloadSize: number;
|
|
16
|
+
};
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
export interface ApprovalResponse {
|
|
@@ -16,7 +23,7 @@ export interface ApprovalResponse {
|
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export interface ApprovalAccepted {
|
|
19
|
-
toolName:
|
|
26
|
+
toolName: string;
|
|
20
27
|
args: Record<string, unknown>;
|
|
21
28
|
}
|
|
22
29
|
|
|
@@ -59,7 +66,7 @@ export function subscribeApprovalAccepted(listener: ApprovalAcceptedListener): (
|
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
68
|
|
|
62
|
-
function notifyApprovalAccepted(toolName:
|
|
69
|
+
function notifyApprovalAccepted(toolName: string, args: Record<string, unknown>): void {
|
|
63
70
|
for (const listener of acceptedListeners) {
|
|
64
71
|
listener({ toolName, args });
|
|
65
72
|
}
|
|
@@ -70,15 +77,20 @@ export function getCurrentApproval(): ApprovalRequest | null {
|
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
export async function requestApproval(
|
|
73
|
-
toolName:
|
|
80
|
+
toolName: string,
|
|
74
81
|
args: Record<string, unknown>,
|
|
75
82
|
preview: { title: string; content: string; details?: string[] }
|
|
76
83
|
): Promise<{ approved: boolean; customResponse?: string }> {
|
|
84
|
+
const mcpMeta = (args as any).__mcpMeta;
|
|
85
|
+
const cleanArgs = { ...args };
|
|
86
|
+
delete (cleanArgs as any).__mcpMeta;
|
|
87
|
+
|
|
77
88
|
const request: ApprovalRequest = {
|
|
78
89
|
id: createId(),
|
|
79
90
|
toolName,
|
|
80
91
|
preview,
|
|
81
|
-
args,
|
|
92
|
+
args: cleanArgs,
|
|
93
|
+
...(mcpMeta && { mcpMeta }),
|
|
82
94
|
};
|
|
83
95
|
|
|
84
96
|
const response = await new Promise<ApprovalResponse>((resolve, reject) => {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Command, CommandResult } from './types';
|
|
2
|
+
|
|
3
|
+
export const compactCommand: Command = {
|
|
4
|
+
name: 'compact',
|
|
5
|
+
description: 'Compact the current conversation context',
|
|
6
|
+
usage: '/compact [maxTokens]',
|
|
7
|
+
execute: (args: string[]): CommandResult => {
|
|
8
|
+
let maxTokens: number | undefined;
|
|
9
|
+
if (args[0]) {
|
|
10
|
+
const parsed = Number(args[0]);
|
|
11
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
content: 'Invalid maxTokens. Usage: /compact [maxTokens]',
|
|
15
|
+
shouldAddToHistory: false
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
maxTokens = Math.floor(parsed);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
success: true,
|
|
23
|
+
content: 'Conversation compacted.',
|
|
24
|
+
shouldAddToHistory: false,
|
|
25
|
+
shouldCompactMessages: true,
|
|
26
|
+
compactMaxTokens: maxTokens,
|
|
27
|
+
shouldClearMessages: true
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -5,7 +5,7 @@ export const echoCommand: Command = {
|
|
|
5
5
|
description: 'Echo the provided text back to the user',
|
|
6
6
|
usage: '/echo <text>',
|
|
7
7
|
aliases: ['e'],
|
|
8
|
-
execute: (args: string[],
|
|
8
|
+
execute: (args: string[], _fullCommand: string): { success: boolean; content: string } => {
|
|
9
9
|
if (args.length === 0) {
|
|
10
10
|
return {
|
|
11
11
|
success: false,
|
|
@@ -3,12 +3,11 @@ import { commandRegistry } from './registry';
|
|
|
3
3
|
import { echoCommand } from './echo';
|
|
4
4
|
import { helpCommand } from './help';
|
|
5
5
|
import { initCommand } from './init';
|
|
6
|
-
import { undoCommand } from './undo';
|
|
7
|
-
import { redoCommand } from './redo';
|
|
8
|
-
import { sessionsCommand } from './sessions';
|
|
9
6
|
import { webCommand } from './web';
|
|
10
7
|
import { imageCommand } from './image';
|
|
11
8
|
import { approvalsCommand } from './approvals';
|
|
9
|
+
import { newCommand } from './new';
|
|
10
|
+
import { compactCommand } from './compact';
|
|
12
11
|
|
|
13
12
|
export { commandRegistry } from './registry';
|
|
14
13
|
export type { Command, CommandResult, CommandRegistry } from './types';
|
|
@@ -63,10 +62,9 @@ export function initializeCommands(): void {
|
|
|
63
62
|
commandRegistry.register(echoCommand);
|
|
64
63
|
commandRegistry.register(helpCommand);
|
|
65
64
|
commandRegistry.register(initCommand);
|
|
66
|
-
commandRegistry.register(undoCommand);
|
|
67
|
-
commandRegistry.register(redoCommand);
|
|
68
|
-
commandRegistry.register(sessionsCommand);
|
|
69
65
|
commandRegistry.register(webCommand);
|
|
70
66
|
commandRegistry.register(imageCommand);
|
|
71
67
|
commandRegistry.register(approvalsCommand);
|
|
68
|
+
commandRegistry.register(newCommand);
|
|
69
|
+
commandRegistry.register(compactCommand);
|
|
72
70
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Command, CommandResult } from './types';
|
|
2
|
+
|
|
3
|
+
export const newCommand: Command = {
|
|
4
|
+
name: 'new',
|
|
5
|
+
description: 'Start a new chat',
|
|
6
|
+
usage: '/new',
|
|
7
|
+
aliases: ['clear'],
|
|
8
|
+
execute: (_args: string[], _fullCommand: string): CommandResult => {
|
|
9
|
+
return {
|
|
10
|
+
success: true,
|
|
11
|
+
content: 'Starting a new chat...',
|
|
12
|
+
shouldClearMessages: true
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
};
|
package/src/utils/config.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface MosaicConfig {
|
|
|
38
38
|
model?: string;
|
|
39
39
|
apiKey?: string;
|
|
40
40
|
systemPrompt?: string;
|
|
41
|
+
maxSteps?: number;
|
|
42
|
+
maxContextTokens?: number;
|
|
41
43
|
customProviders?: CustomProvider[];
|
|
42
44
|
customModels?: { [providerId: string]: AIModel[] };
|
|
43
45
|
requireApprovals?: boolean;
|
|
@@ -354,4 +356,4 @@ export function clearRecentProjects(): void {
|
|
|
354
356
|
const config = readConfig();
|
|
355
357
|
config.recentProjects = [];
|
|
356
358
|
writeConfig(config);
|
|
357
|
-
}
|
|
359
|
+
}
|
|
@@ -34,8 +34,6 @@ export function renderDiffLine(line: string, key: string) {
|
|
|
34
34
|
|
|
35
35
|
export function renderInlineDiffLine(content: string) {
|
|
36
36
|
const parsed = parseDiffLine(content);
|
|
37
|
-
const colors = getDiffLineColors(parsed);
|
|
38
|
-
|
|
39
37
|
if (parsed.isDiffLine) {
|
|
40
38
|
return (
|
|
41
39
|
<>
|
|
@@ -56,6 +54,6 @@ export function renderInlineDiffLine(content: string) {
|
|
|
56
54
|
return null;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
export function getDiffLineBackground(
|
|
57
|
+
export function getDiffLineBackground(_content: string): string | null {
|
|
60
58
|
return null;
|
|
61
59
|
}
|
|
@@ -15,6 +15,7 @@ interface ExploreBridgeGlobal {
|
|
|
15
15
|
toolCallback: ExploreToolCallback | null;
|
|
16
16
|
totalExploreTokens: number;
|
|
17
17
|
subscribers: Set<ExploreToolSubscriber>;
|
|
18
|
+
parentContext: string;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
const globalKey = '__mosaic_explore_bridge__';
|
|
@@ -26,6 +27,7 @@ if (!g[globalKey]) {
|
|
|
26
27
|
toolCallback: null,
|
|
27
28
|
totalExploreTokens: 0,
|
|
28
29
|
subscribers: new Set<ExploreToolSubscriber>(),
|
|
30
|
+
parentContext: '',
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -85,3 +87,11 @@ export function subscribeExploreTool(callback: ExploreToolSubscriber): () => voi
|
|
|
85
87
|
export function getExploreTokens(): number {
|
|
86
88
|
return state.totalExploreTokens;
|
|
87
89
|
}
|
|
90
|
+
|
|
91
|
+
export function setExploreContext(context: string): void {
|
|
92
|
+
state.parentContext = context;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getExploreContext(): string {
|
|
96
|
+
return state.parentContext;
|
|
97
|
+
}
|