@aiscene/shared 8.0.1 → 8.0.3
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/dist/es/cli/cli-args.mjs +95 -0
- package/dist/es/cli/cli-error.mjs +24 -0
- package/dist/es/cli/cli-runner.mjs +10 -40
- package/dist/es/cli/index.mjs +4 -2
- package/dist/es/constants/example-code.mjs +2 -2
- package/dist/es/constants/index.mjs +6 -1
- package/dist/es/env/model-config-manager.mjs +3 -0
- package/dist/es/env/parse-model-config.mjs +6 -1
- package/dist/es/env/types.mjs +2 -1
- package/dist/es/env/utils.mjs +1 -9
- package/dist/es/extractor/index.mjs +2 -2
- package/dist/es/img/index.mjs +2 -2
- package/dist/es/img/info.mjs +7 -1
- package/dist/es/key-alias-utils.mjs +19 -0
- package/dist/es/mcp/base-server.mjs +10 -9
- package/dist/es/mcp/base-tools.mjs +72 -4
- package/dist/es/mcp/cli-report-session.mjs +78 -0
- package/dist/es/mcp/error-formatter.mjs +19 -0
- package/dist/es/mcp/index.mjs +2 -0
- package/dist/es/mcp/init-arg-utils.mjs +38 -0
- package/dist/es/mcp/inject-report-html-plugin.mjs +1 -1
- package/dist/es/mcp/tool-generator.mjs +65 -17
- package/dist/es/node/fs.mjs +1 -1
- package/dist/lib/cli/cli-args.js +138 -0
- package/dist/lib/cli/cli-error.js +61 -0
- package/dist/lib/cli/cli-runner.js +19 -46
- package/dist/lib/cli/index.js +8 -3
- package/dist/lib/constants/example-code.js +2 -2
- package/dist/lib/constants/index.js +23 -3
- package/dist/lib/env/model-config-manager.js +3 -0
- package/dist/lib/env/parse-model-config.js +6 -1
- package/dist/lib/env/types.js +4 -0
- package/dist/lib/env/utils.js +0 -11
- package/dist/lib/extractor/index.js +3 -0
- package/dist/lib/img/index.js +3 -0
- package/dist/lib/img/info.js +10 -1
- package/dist/lib/key-alias-utils.js +62 -0
- package/dist/lib/mcp/base-server.js +11 -10
- package/dist/lib/mcp/base-tools.js +74 -6
- package/dist/lib/mcp/cli-report-session.js +121 -0
- package/dist/lib/mcp/error-formatter.js +53 -0
- package/dist/lib/mcp/index.js +24 -10
- package/dist/lib/mcp/init-arg-utils.js +78 -0
- package/dist/lib/mcp/inject-report-html-plugin.js +1 -1
- package/dist/lib/mcp/tool-generator.js +74 -26
- package/dist/lib/node/fs.js +1 -1
- package/dist/types/cli/cli-args.d.ts +8 -0
- package/dist/types/cli/cli-error.d.ts +5 -0
- package/dist/types/cli/cli-runner.d.ts +4 -7
- package/dist/types/cli/index.d.ts +3 -1
- package/dist/types/constants/example-code.d.ts +1 -1
- package/dist/types/constants/index.d.ts +5 -0
- package/dist/types/env/types.d.ts +10 -2
- package/dist/types/env/utils.d.ts +0 -31
- package/dist/types/extractor/index.d.ts +1 -1
- package/dist/types/img/index.d.ts +1 -1
- package/dist/types/img/info.d.ts +5 -0
- package/dist/types/key-alias-utils.d.ts +9 -0
- package/dist/types/mcp/base-tools.d.ts +74 -5
- package/dist/types/mcp/cli-report-session.d.ts +12 -0
- package/dist/types/mcp/error-formatter.d.ts +12 -0
- package/dist/types/mcp/index.d.ts +2 -0
- package/dist/types/mcp/init-arg-utils.d.ts +13 -0
- package/dist/types/mcp/inject-report-html-plugin.d.ts +2 -2
- package/dist/types/mcp/launcher-helper.d.ts +3 -3
- package/dist/types/mcp/tool-generator.d.ts +3 -3
- package/dist/types/mcp/types.d.ts +9 -0
- package/package.json +1 -1
- package/src/cli/cli-args.ts +173 -0
- package/src/cli/cli-error.ts +24 -0
- package/src/cli/cli-runner.ts +37 -56
- package/src/cli/index.ts +3 -7
- package/src/constants/example-code.ts +2 -2
- package/src/constants/index.ts +10 -0
- package/src/env/model-config-manager.ts +3 -0
- package/src/env/parse-model-config.ts +19 -1
- package/src/env/types.ts +11 -2
- package/src/env/utils.ts +0 -50
- package/src/extractor/index.ts +1 -1
- package/src/img/index.ts +2 -0
- package/src/img/info.ts +27 -0
- package/src/key-alias-utils.ts +23 -0
- package/src/mcp/base-server.ts +10 -12
- package/src/mcp/base-tools.ts +218 -11
- package/src/mcp/cli-report-session.ts +130 -0
- package/src/mcp/error-formatter.ts +52 -0
- package/src/mcp/index.ts +2 -0
- package/src/mcp/init-arg-utils.ts +105 -0
- package/src/mcp/inject-report-html-plugin.ts +3 -3
- package/src/mcp/launcher-helper.ts +3 -3
- package/src/mcp/tool-generator.ts +98 -20
- package/src/mcp/types.ts +16 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseBase64 } from '
|
|
1
|
+
import { parseBase64 } from '@aiscene/shared/img';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import {
|
|
4
4
|
getZodDescription,
|
|
@@ -6,20 +6,16 @@ import {
|
|
|
6
6
|
isMidsceneLocatorField,
|
|
7
7
|
unwrapZodField,
|
|
8
8
|
} from '../zod-schema-utils';
|
|
9
|
+
import { getErrorMessage } from './error-formatter';
|
|
9
10
|
import type {
|
|
10
11
|
ActionSpaceItem,
|
|
11
12
|
BaseAgent,
|
|
13
|
+
ToolCliMetadata,
|
|
12
14
|
ToolDefinition,
|
|
13
15
|
ToolResult,
|
|
16
|
+
ToolSchema,
|
|
14
17
|
} from './types';
|
|
15
18
|
|
|
16
|
-
/**
|
|
17
|
-
* Extract error message from unknown error type
|
|
18
|
-
*/
|
|
19
|
-
function getErrorMessage(error: unknown): string {
|
|
20
|
-
return error instanceof Error ? error.message : String(error);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
19
|
/**
|
|
24
20
|
* Generate MCP tool description from ActionSpaceItem
|
|
25
21
|
* Format: "actionName action, description. Parameters: param1 (type) - desc; param2 (type) - desc"
|
|
@@ -157,10 +153,19 @@ function transformSchemaField(
|
|
|
157
153
|
}
|
|
158
154
|
|
|
159
155
|
/**
|
|
160
|
-
* Extract and transform schema from action's paramSchema
|
|
156
|
+
* Extract and transform schema from action's paramSchema.
|
|
157
|
+
*
|
|
158
|
+
* CLI and MCP both expose parameters as named fields, so the only schema
|
|
159
|
+
* shapes we can surface are ZodObject (any number of fields) or undefined
|
|
160
|
+
* (the action takes no parameters). A primitive schema like `z.string()`
|
|
161
|
+
* silently degraded to leaking the ZodString instance's prototype methods
|
|
162
|
+
* as CLI flags — see https://github.com/web-infra-dev/midscene/issues/2313.
|
|
163
|
+
* Reject such schemas up front so the next author gets a loud error
|
|
164
|
+
* instead of a silent misconfiguration at runtime.
|
|
161
165
|
*/
|
|
162
166
|
function extractActionSchema(
|
|
163
167
|
paramSchema: z.ZodTypeAny | undefined,
|
|
168
|
+
actionName: string,
|
|
164
169
|
): Record<string, z.ZodTypeAny> {
|
|
165
170
|
if (!paramSchema) {
|
|
166
171
|
return {};
|
|
@@ -168,7 +173,12 @@ function extractActionSchema(
|
|
|
168
173
|
|
|
169
174
|
const shape = getZodObjectShape(paramSchema);
|
|
170
175
|
if (!shape) {
|
|
171
|
-
|
|
176
|
+
const typeName =
|
|
177
|
+
(paramSchema as unknown as { _def?: { typeName?: string } })?._def
|
|
178
|
+
?.typeName ?? 'unknown';
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Action "${actionName}" declared a non-object paramSchema (${typeName}). CLI and MCP tool schemas must be a ZodObject (e.g. z.object({ uri: z.string() })) or undefined. Wrap primitive fields in an object schema.`,
|
|
181
|
+
);
|
|
172
182
|
}
|
|
173
183
|
|
|
174
184
|
return Object.fromEntries(
|
|
@@ -453,25 +463,49 @@ async function captureFailureResult(
|
|
|
453
463
|
}
|
|
454
464
|
}
|
|
455
465
|
|
|
466
|
+
function mergeToolCliMetadata(
|
|
467
|
+
base?: ToolCliMetadata,
|
|
468
|
+
extra?: ToolCliMetadata,
|
|
469
|
+
): ToolCliMetadata | undefined {
|
|
470
|
+
const options = {
|
|
471
|
+
...(base?.options ?? {}),
|
|
472
|
+
...(extra?.options ?? {}),
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
return Object.keys(options).length > 0 ? { options } : undefined;
|
|
476
|
+
}
|
|
477
|
+
|
|
456
478
|
/**
|
|
457
479
|
* Converts DeviceAction from actionSpace into MCP ToolDefinition
|
|
458
480
|
* This is the core logic that removes need for hardcoded tool definitions
|
|
459
481
|
*/
|
|
460
482
|
export function generateToolsFromActionSpace(
|
|
461
483
|
actionSpace: ActionSpaceItem[],
|
|
462
|
-
getAgent: () => Promise<BaseAgent>,
|
|
484
|
+
getAgent: (args?: Record<string, unknown>) => Promise<BaseAgent>,
|
|
485
|
+
sanitizeArgs: (args: Record<string, unknown>) => Record<string, unknown> = (
|
|
486
|
+
args,
|
|
487
|
+
) => args,
|
|
488
|
+
initArgSchema: ToolSchema = {},
|
|
489
|
+
initArgCliMetadata?: ToolCliMetadata,
|
|
463
490
|
): ToolDefinition[] {
|
|
464
491
|
return actionSpace.map((action) => {
|
|
465
|
-
const schema =
|
|
492
|
+
const schema = {
|
|
493
|
+
...extractActionSchema(action.paramSchema as z.ZodTypeAny, action.name),
|
|
494
|
+
...initArgSchema,
|
|
495
|
+
};
|
|
466
496
|
|
|
467
497
|
return {
|
|
468
498
|
name: action.name,
|
|
469
499
|
description: describeActionForMCP(action),
|
|
470
500
|
schema,
|
|
501
|
+
cli: initArgCliMetadata,
|
|
471
502
|
handler: async (args: Record<string, unknown>) => {
|
|
472
503
|
try {
|
|
473
|
-
const agent = await getAgent();
|
|
474
|
-
const normalizedArgs = normalizeActionArgs(
|
|
504
|
+
const agent = await getAgent(args);
|
|
505
|
+
const normalizedArgs = normalizeActionArgs(
|
|
506
|
+
sanitizeArgs(args),
|
|
507
|
+
action.paramSchema,
|
|
508
|
+
);
|
|
475
509
|
let actionResult: unknown;
|
|
476
510
|
|
|
477
511
|
try {
|
|
@@ -513,16 +547,23 @@ export function generateToolsFromActionSpace(
|
|
|
513
547
|
* Generate common tools (screenshot, act)
|
|
514
548
|
*/
|
|
515
549
|
export function generateCommonTools(
|
|
516
|
-
getAgent: () => Promise<BaseAgent>,
|
|
550
|
+
getAgent: (args?: Record<string, unknown>) => Promise<BaseAgent>,
|
|
551
|
+
initArgSchema: ToolSchema = {},
|
|
552
|
+
initArgCliMetadata?: ToolCliMetadata,
|
|
517
553
|
): ToolDefinition[] {
|
|
518
554
|
return [
|
|
519
555
|
{
|
|
520
556
|
name: 'take_screenshot',
|
|
521
557
|
description: 'Capture screenshot of current page/screen',
|
|
522
|
-
schema: {
|
|
523
|
-
|
|
558
|
+
schema: {
|
|
559
|
+
...initArgSchema,
|
|
560
|
+
},
|
|
561
|
+
cli: initArgCliMetadata,
|
|
562
|
+
handler: async (
|
|
563
|
+
args: Record<string, unknown> = {},
|
|
564
|
+
): Promise<ToolResult> => {
|
|
524
565
|
try {
|
|
525
|
-
const agent = await getAgent();
|
|
566
|
+
const agent = await getAgent(args);
|
|
526
567
|
const screenshot = await agent.page?.screenshotBase64();
|
|
527
568
|
if (!screenshot) {
|
|
528
569
|
return createErrorResult('Screenshot not available');
|
|
@@ -550,11 +591,15 @@ export function generateCommonTools(
|
|
|
550
591
|
.describe(
|
|
551
592
|
'Natural language description of the action to perform, e.g. "press Command+Space, type Safari, press Enter"',
|
|
552
593
|
),
|
|
594
|
+
...initArgSchema,
|
|
553
595
|
},
|
|
554
|
-
|
|
596
|
+
cli: mergeToolCliMetadata(undefined, initArgCliMetadata),
|
|
597
|
+
handler: async (
|
|
598
|
+
args: Record<string, unknown> = {},
|
|
599
|
+
): Promise<ToolResult> => {
|
|
555
600
|
const prompt = args.prompt as string;
|
|
556
601
|
try {
|
|
557
|
-
const agent = await getAgent();
|
|
602
|
+
const agent = await getAgent(args);
|
|
558
603
|
if (!agent.aiAction) {
|
|
559
604
|
return createErrorResult('act is not supported by this agent');
|
|
560
605
|
}
|
|
@@ -576,5 +621,38 @@ export function generateCommonTools(
|
|
|
576
621
|
}
|
|
577
622
|
},
|
|
578
623
|
},
|
|
624
|
+
{
|
|
625
|
+
name: 'assert',
|
|
626
|
+
description:
|
|
627
|
+
'Assert a natural language statement against the current page/screen.',
|
|
628
|
+
schema: {
|
|
629
|
+
prompt: z
|
|
630
|
+
.string()
|
|
631
|
+
.describe(
|
|
632
|
+
'Natural language assertion to verify, e.g. "there is a login button visible"',
|
|
633
|
+
),
|
|
634
|
+
...initArgSchema,
|
|
635
|
+
},
|
|
636
|
+
cli: mergeToolCliMetadata(undefined, initArgCliMetadata),
|
|
637
|
+
handler: async (
|
|
638
|
+
args: Record<string, unknown> = {},
|
|
639
|
+
): Promise<ToolResult> => {
|
|
640
|
+
const prompt = args.prompt as string;
|
|
641
|
+
try {
|
|
642
|
+
const agent = await getAgent(args);
|
|
643
|
+
if (!agent.aiAssert) {
|
|
644
|
+
return createErrorResult('assert is not supported by this agent');
|
|
645
|
+
}
|
|
646
|
+
await agent.aiAssert(prompt);
|
|
647
|
+
return {
|
|
648
|
+
content: [{ type: 'text', text: 'Assertion passed.' }],
|
|
649
|
+
};
|
|
650
|
+
} catch (error: unknown) {
|
|
651
|
+
const errorMessage = getErrorMessage(error);
|
|
652
|
+
console.error('Error executing assert:', errorMessage);
|
|
653
|
+
return createErrorResult(`Failed to execute assert: ${errorMessage}`);
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
},
|
|
579
657
|
];
|
|
580
658
|
}
|
package/src/mcp/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { z } from 'zod';
|
|
3
3
|
|
|
4
|
-
// Avoid circular dependency: don't import from @
|
|
4
|
+
// Avoid circular dependency: don't import from @aiscene/core
|
|
5
5
|
// Instead, use generic types that will be provided by implementation
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -47,6 +47,15 @@ export type ToolHandler<T = Record<string, unknown>> = (
|
|
|
47
47
|
*/
|
|
48
48
|
export type ToolSchema = Record<string, z.ZodTypeAny>;
|
|
49
49
|
|
|
50
|
+
export interface ToolCliOption {
|
|
51
|
+
preferredName?: string;
|
|
52
|
+
aliases?: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ToolCliMetadata {
|
|
56
|
+
options?: Record<string, ToolCliOption>;
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
/**
|
|
51
60
|
* Tool definition for MCP server
|
|
52
61
|
*/
|
|
@@ -55,6 +64,7 @@ export interface ToolDefinition<T = Record<string, unknown>> {
|
|
|
55
64
|
description: string;
|
|
56
65
|
schema: ToolSchema;
|
|
57
66
|
handler: ToolHandler<T>;
|
|
67
|
+
cli?: ToolCliMetadata;
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
/**
|
|
@@ -96,6 +106,11 @@ export interface BaseAgent {
|
|
|
96
106
|
assertion: string,
|
|
97
107
|
options: Record<string, unknown>,
|
|
98
108
|
) => Promise<unknown>;
|
|
109
|
+
aiAssert?: (
|
|
110
|
+
assertion: string,
|
|
111
|
+
msg?: string,
|
|
112
|
+
options?: Record<string, unknown>,
|
|
113
|
+
) => Promise<unknown>;
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
/**
|