@kirosnn/mosaic 0.0.91 → 0.71.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/LICENSE +1 -1
- package/README.md +2 -2
- package/package.json +52 -47
- package/src/agent/prompts/systemPrompt.ts +198 -68
- package/src/agent/prompts/toolsPrompt.ts +217 -135
- package/src/agent/provider/anthropic.ts +19 -15
- package/src/agent/provider/google.ts +21 -17
- package/src/agent/provider/ollama.ts +80 -41
- package/src/agent/provider/openai.ts +107 -67
- package/src/agent/provider/reasoning.ts +29 -0
- package/src/agent/provider/xai.ts +19 -15
- package/src/agent/tools/definitions.ts +9 -5
- package/src/agent/tools/executor.ts +655 -46
- package/src/agent/tools/exploreExecutor.ts +12 -12
- package/src/agent/tools/fetch.ts +58 -0
- package/src/agent/tools/glob.ts +20 -4
- package/src/agent/tools/grep.ts +62 -8
- package/src/agent/tools/plan.ts +27 -0
- package/src/agent/tools/read.ts +2 -0
- package/src/agent/types.ts +6 -6
- package/src/components/App.tsx +67 -25
- package/src/components/CustomInput.tsx +274 -68
- package/src/components/Main.tsx +323 -168
- package/src/components/ShortcutsModal.tsx +11 -8
- package/src/components/main/ChatPage.tsx +217 -58
- package/src/components/main/HomePage.tsx +5 -1
- package/src/components/main/ThinkingIndicator.tsx +11 -1
- package/src/components/main/types.ts +11 -10
- package/src/index.tsx +3 -5
- package/src/utils/approvalBridge.ts +29 -8
- package/src/utils/approvalModeBridge.ts +17 -0
- package/src/utils/commands/approvals.ts +48 -0
- package/src/utils/commands/image.ts +109 -0
- package/src/utils/commands/index.ts +5 -1
- package/src/utils/diffRendering.tsx +13 -14
- package/src/utils/history.ts +82 -40
- package/src/utils/imageBridge.ts +28 -0
- package/src/utils/images.ts +31 -0
- package/src/utils/models.ts +0 -7
- package/src/utils/notificationBridge.ts +23 -0
- package/src/utils/toolFormatting.ts +162 -43
- package/src/web/app.tsx +94 -34
- package/src/web/assets/css/ChatPage.css +102 -30
- package/src/web/assets/css/MessageItem.css +26 -29
- package/src/web/assets/css/ThinkingIndicator.css +44 -6
- package/src/web/assets/css/ToolMessage.css +36 -14
- package/src/web/components/ChatPage.tsx +228 -105
- package/src/web/components/HomePage.tsx +6 -6
- package/src/web/components/MessageItem.tsx +88 -89
- package/src/web/components/Setup.tsx +1 -1
- package/src/web/components/Sidebar.tsx +1 -1
- package/src/web/components/ThinkingIndicator.tsx +40 -21
- package/src/web/router.ts +1 -1
- package/src/web/server.tsx +187 -39
- package/src/web/storage.ts +23 -1
- package/src/web/types.ts +7 -6
|
@@ -1,15 +1,90 @@
|
|
|
1
|
-
import { streamText, CoreMessage } from 'ai';
|
|
2
|
-
import { createOpenAI } from '@ai-sdk/openai';
|
|
3
|
-
import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
|
|
1
|
+
import { streamText, CoreMessage, CoreTool } from 'ai';
|
|
2
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
3
|
+
import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { shouldEnableReasoning } from './reasoning';
|
|
6
|
+
|
|
7
|
+
function unwrapOptional(schema: z.ZodTypeAny): z.ZodTypeAny {
|
|
8
|
+
if (schema instanceof z.ZodOptional) {
|
|
9
|
+
return unwrapOptional(schema.unwrap());
|
|
10
|
+
}
|
|
11
|
+
if (schema instanceof z.ZodEffects) {
|
|
12
|
+
const inner = unwrapOptional(schema.innerType());
|
|
13
|
+
return inner === schema.innerType() ? schema : new z.ZodEffects({
|
|
14
|
+
...schema._def,
|
|
15
|
+
schema: inner,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return schema;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function makeAllPropertiesRequired(schema: z.ZodTypeAny): z.ZodTypeAny {
|
|
22
|
+
if (schema instanceof z.ZodEffects) {
|
|
23
|
+
const innerTransformed = makeAllPropertiesRequired(schema.innerType());
|
|
24
|
+
return new z.ZodEffects({
|
|
25
|
+
...schema._def,
|
|
26
|
+
schema: innerTransformed,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (schema instanceof z.ZodObject) {
|
|
31
|
+
const shape = schema.shape;
|
|
32
|
+
const newShape: Record<string, z.ZodTypeAny> = {};
|
|
33
|
+
for (const key in shape) {
|
|
34
|
+
let fieldSchema = shape[key];
|
|
35
|
+
fieldSchema = unwrapOptional(fieldSchema);
|
|
36
|
+
if (fieldSchema instanceof z.ZodObject) {
|
|
37
|
+
fieldSchema = makeAllPropertiesRequired(fieldSchema);
|
|
38
|
+
} else if (fieldSchema instanceof z.ZodArray) {
|
|
39
|
+
const innerType = fieldSchema.element;
|
|
40
|
+
if (innerType instanceof z.ZodObject) {
|
|
41
|
+
fieldSchema = z.array(makeAllPropertiesRequired(innerType));
|
|
42
|
+
}
|
|
43
|
+
} else if (fieldSchema instanceof z.ZodEffects) {
|
|
44
|
+
const innerType = fieldSchema.innerType();
|
|
45
|
+
if (innerType instanceof z.ZodObject) {
|
|
46
|
+
fieldSchema = new z.ZodEffects({
|
|
47
|
+
...fieldSchema._def,
|
|
48
|
+
schema: makeAllPropertiesRequired(innerType),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
newShape[key] = fieldSchema;
|
|
53
|
+
}
|
|
54
|
+
return z.object(newShape);
|
|
55
|
+
}
|
|
56
|
+
return schema;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function transformToolsForResponsesApi(
|
|
60
|
+
tools: Record<string, CoreTool> | undefined
|
|
61
|
+
): Record<string, CoreTool> | undefined {
|
|
62
|
+
if (!tools) return tools;
|
|
63
|
+
|
|
64
|
+
const transformed: Record<string, CoreTool> = {};
|
|
65
|
+
for (const [name, tool] of Object.entries(tools)) {
|
|
66
|
+
const t = tool as any;
|
|
67
|
+
if (t.parameters) {
|
|
68
|
+
transformed[name] = {
|
|
69
|
+
...t,
|
|
70
|
+
parameters: makeAllPropertiesRequired(t.parameters),
|
|
71
|
+
};
|
|
72
|
+
} else {
|
|
73
|
+
transformed[name] = tool;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return transformed;
|
|
77
|
+
}
|
|
4
78
|
|
|
5
79
|
export class OpenAIProvider implements Provider {
|
|
6
|
-
async *sendMessage(
|
|
7
|
-
messages: CoreMessage[],
|
|
8
|
-
config: ProviderConfig,
|
|
9
|
-
options?: ProviderSendOptions
|
|
10
|
-
): AsyncGenerator<AgentEvent> {
|
|
11
|
-
const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
|
|
12
|
-
const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
|
|
80
|
+
async *sendMessage(
|
|
81
|
+
messages: CoreMessage[],
|
|
82
|
+
config: ProviderConfig,
|
|
83
|
+
options?: ProviderSendOptions
|
|
84
|
+
): AsyncGenerator<AgentEvent> {
|
|
85
|
+
const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
|
|
86
|
+
const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
|
|
87
|
+
const reasoningEnabled = await shouldEnableReasoning(config.provider, cleanModel);
|
|
13
88
|
|
|
14
89
|
const openai = createOpenAI({
|
|
15
90
|
apiKey: cleanApiKey,
|
|
@@ -32,20 +107,25 @@ export class OpenAIProvider implements Provider {
|
|
|
32
107
|
endpoint: OpenAIEndpoint,
|
|
33
108
|
strictJsonSchema: boolean
|
|
34
109
|
): AsyncGenerator<AgentEvent> {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
110
|
+
const toolsToUse =
|
|
111
|
+
endpoint === 'responses'
|
|
112
|
+
? transformToolsForResponsesApi(config.tools)
|
|
113
|
+
: config.tools;
|
|
114
|
+
|
|
115
|
+
const result = streamText({
|
|
116
|
+
model: pickModel(endpoint),
|
|
117
|
+
messages: messages,
|
|
118
|
+
system: config.systemPrompt,
|
|
119
|
+
tools: toolsToUse,
|
|
120
|
+
maxSteps: config.maxSteps ?? 10,
|
|
121
|
+
abortSignal: options?.abortSignal,
|
|
122
|
+
providerOptions: {
|
|
123
|
+
openai: {
|
|
124
|
+
strictJsonSchema,
|
|
125
|
+
...(reasoningEnabled ? { reasoningEffort: 'high' } : {}),
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
});
|
|
49
129
|
|
|
50
130
|
let stepCounter = 0;
|
|
51
131
|
|
|
@@ -150,59 +230,19 @@ export class OpenAIProvider implements Provider {
|
|
|
150
230
|
};
|
|
151
231
|
|
|
152
232
|
try {
|
|
153
|
-
yield* run('responses',
|
|
233
|
+
yield* run('responses', false);
|
|
154
234
|
} catch (error) {
|
|
155
235
|
if (options?.abortSignal?.aborted) return;
|
|
156
236
|
const msg = error instanceof Error ? error.message : String(error);
|
|
157
|
-
const looksLikeStrictSchemaError =
|
|
158
|
-
msg.includes('Invalid schema for function') &&
|
|
159
|
-
msg.includes('required') &&
|
|
160
|
-
msg.includes('properties');
|
|
161
|
-
|
|
162
|
-
if (looksLikeStrictSchemaError) {
|
|
163
|
-
try {
|
|
164
|
-
yield* run('responses', false);
|
|
165
|
-
return;
|
|
166
|
-
} catch (retryError) {
|
|
167
|
-
if (options?.abortSignal?.aborted) return;
|
|
168
|
-
yield {
|
|
169
|
-
type: 'error',
|
|
170
|
-
error: retryError instanceof Error ? retryError.message : 'Unknown error occurred',
|
|
171
|
-
};
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
237
|
|
|
176
238
|
const fallbackEndpoint = classifyEndpointError(msg);
|
|
177
239
|
if (fallbackEndpoint && fallbackEndpoint !== 'responses') {
|
|
178
240
|
try {
|
|
179
|
-
yield* run(fallbackEndpoint,
|
|
241
|
+
yield* run(fallbackEndpoint, false);
|
|
180
242
|
return;
|
|
181
243
|
} catch (endpointError) {
|
|
182
244
|
if (options?.abortSignal?.aborted) return;
|
|
183
245
|
const endpointMsg = endpointError instanceof Error ? endpointError.message : String(endpointError);
|
|
184
|
-
const strictSchemaFromFallback =
|
|
185
|
-
endpointMsg.includes('Invalid schema for function') &&
|
|
186
|
-
endpointMsg.includes('required') &&
|
|
187
|
-
endpointMsg.includes('properties');
|
|
188
|
-
|
|
189
|
-
if (strictSchemaFromFallback) {
|
|
190
|
-
try {
|
|
191
|
-
yield* run(fallbackEndpoint, false);
|
|
192
|
-
return;
|
|
193
|
-
} catch (endpointRetryError) {
|
|
194
|
-
if (options?.abortSignal?.aborted) return;
|
|
195
|
-
yield {
|
|
196
|
-
type: 'error',
|
|
197
|
-
error:
|
|
198
|
-
endpointRetryError instanceof Error
|
|
199
|
-
? endpointRetryError.message
|
|
200
|
-
: 'Unknown error occurred',
|
|
201
|
-
};
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
246
|
yield {
|
|
207
247
|
type: 'error',
|
|
208
248
|
error: endpointMsg || 'Unknown error occurred',
|
|
@@ -217,4 +257,4 @@ export class OpenAIProvider implements Provider {
|
|
|
217
257
|
};
|
|
218
258
|
}
|
|
219
259
|
}
|
|
220
|
-
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { findModelsDevModelById, getModelsDevModel } from '../../utils/models';
|
|
2
|
+
|
|
3
|
+
function normalizeId(value: string): string {
|
|
4
|
+
return value.trim();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function matchesReasoningHeuristic(modelId: string): boolean {
|
|
8
|
+
const id = modelId.toLowerCase();
|
|
9
|
+
return id.includes('reasoning') || id.includes('o1') || id.includes('o3') || id.includes('r1');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function shouldEnableReasoning(providerId: string, modelId: string): Promise<boolean> {
|
|
13
|
+
const provider = normalizeId(providerId);
|
|
14
|
+
const model = normalizeId(modelId);
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const direct = await getModelsDevModel(provider, model);
|
|
18
|
+
if (direct && typeof direct.reasoning === 'boolean') return direct.reasoning;
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const byId = await findModelsDevModelById(model);
|
|
24
|
+
if (byId?.model && typeof byId.model.reasoning === 'boolean') return byId.model.reasoning;
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return matchesReasoningHeuristic(model);
|
|
29
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { streamText, CoreMessage } from 'ai';
|
|
2
|
-
import { createXai } from '@ai-sdk/xai';
|
|
3
|
-
import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
|
|
1
|
+
import { streamText, CoreMessage } from 'ai';
|
|
2
|
+
import { createXai } from '@ai-sdk/xai';
|
|
3
|
+
import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
|
|
4
|
+
import { shouldEnableReasoning } from './reasoning';
|
|
4
5
|
|
|
5
6
|
export class XaiProvider implements Provider {
|
|
6
7
|
async *sendMessage(
|
|
@@ -8,8 +9,9 @@ export class XaiProvider implements Provider {
|
|
|
8
9
|
config: ProviderConfig,
|
|
9
10
|
options?: ProviderSendOptions
|
|
10
11
|
): AsyncGenerator<AgentEvent> {
|
|
11
|
-
const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
|
|
12
|
-
const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
|
|
12
|
+
const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
|
|
13
|
+
const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
|
|
14
|
+
const reasoningEnabled = await shouldEnableReasoning(config.provider, cleanModel);
|
|
13
15
|
|
|
14
16
|
const xai = createXai({
|
|
15
17
|
apiKey: cleanApiKey,
|
|
@@ -19,15 +21,17 @@ export class XaiProvider implements Provider {
|
|
|
19
21
|
model: xai(cleanModel),
|
|
20
22
|
messages: messages,
|
|
21
23
|
system: config.systemPrompt,
|
|
22
|
-
tools: config.tools,
|
|
23
|
-
maxSteps: config.maxSteps || 10,
|
|
24
|
-
abortSignal: options?.abortSignal,
|
|
25
|
-
providerOptions:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
tools: config.tools,
|
|
25
|
+
maxSteps: config.maxSteps || 10,
|
|
26
|
+
abortSignal: options?.abortSignal,
|
|
27
|
+
providerOptions: reasoningEnabled
|
|
28
|
+
? {
|
|
29
|
+
xai: {
|
|
30
|
+
reasoningEffort: 'high',
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
: undefined,
|
|
34
|
+
});
|
|
31
35
|
|
|
32
36
|
try {
|
|
33
37
|
let stepCounter = 0;
|
|
@@ -119,4 +123,4 @@ export class XaiProvider implements Provider {
|
|
|
119
123
|
};
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
|
-
}
|
|
126
|
+
}
|
|
@@ -8,7 +8,9 @@ import { glob } from './glob.ts';
|
|
|
8
8
|
import { grep } from './grep.ts';
|
|
9
9
|
import { edit } from './edit.ts';
|
|
10
10
|
import { question } from './question.ts';
|
|
11
|
-
import { explore } from './explore.ts';
|
|
11
|
+
import { explore } from './explore.ts';
|
|
12
|
+
import { fetch } from './fetch.ts';
|
|
13
|
+
import { plan } from './plan.ts';
|
|
12
14
|
|
|
13
15
|
export const tools: Record<string, CoreTool> = {
|
|
14
16
|
read,
|
|
@@ -18,10 +20,12 @@ export const tools: Record<string, CoreTool> = {
|
|
|
18
20
|
glob,
|
|
19
21
|
grep,
|
|
20
22
|
edit,
|
|
21
|
-
question,
|
|
22
|
-
explore,
|
|
23
|
-
|
|
23
|
+
question,
|
|
24
|
+
explore,
|
|
25
|
+
fetch,
|
|
26
|
+
plan,
|
|
27
|
+
};
|
|
24
28
|
|
|
25
29
|
export function getTools(): Record<string, CoreTool> {
|
|
26
30
|
return tools;
|
|
27
|
-
}
|
|
31
|
+
}
|