Skip to content

Commit 21309a9

Browse files
authored
Merge pull request #5 from Serverless-Devs/integration
mastra integration
2 parents c805e17 + 22133d6 commit 21309a9

40 files changed

+8800
-170
lines changed

examples/mastra.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Agent } from '@mastra/core/agent';
2+
import { AgentRunServer, type AgentRequest } from '../src/server';
3+
import {
4+
MastraConverter,
5+
type AgentEventItem,
6+
model,
7+
toolset,
8+
} from '../src/integration/mastra';
9+
10+
import { logger } from '../src/utils/log';
11+
12+
const mastraAgent = new Agent({
13+
id: 'run_agent',
14+
name: 'AgentRun',
15+
instructions: `
16+
你是一个智能助手,你会帮助用户完成各种任务。你的输出后,必须是返向输出的。
17+
18+
如,用户输入 “你好”,应该输出 “?么的您助帮以可么什有,好您”
19+
`.trim(),
20+
model: () => model({ name: 'ohyee-test' }),
21+
tools: () => toolset({ name: 'start-mcp-time-ggda' }),
22+
});
23+
24+
async function* invokeAgent(
25+
request: AgentRequest,
26+
): AsyncGenerator<AgentEventItem> {
27+
const converter = new MastraConverter();
28+
const mastraStream = await mastraAgent.stream(
29+
request.messages.map(
30+
(msg) =>
31+
({
32+
role: msg.role,
33+
content: msg.content || '',
34+
}) as any,
35+
),
36+
);
37+
for await (const chunk of mastraStream.fullStream) {
38+
const events = converter.convert(chunk);
39+
40+
for (const event of events) {
41+
yield event;
42+
}
43+
}
44+
}
45+
46+
const server = new AgentRunServer({
47+
invokeAgent,
48+
config: { corsOrigins: ['*'] },
49+
});
50+
51+
logger.info(`
52+
curl http://127.0.0.1:9000/openai/v1/chat/completions -X POST \\
53+
-H "Content-Type: application/json" \\
54+
-d \'{"messages": [{"role": "user", "content": "Hello!"}], "stream": true}\'
55+
56+
curl http://127.0.0.1:9000/ag-ui/agent -X POST \\
57+
-H "Content-Type: application/json" \\
58+
-d \'{"messages": [{"role": "user", "content": "Hello!"}]}\'
59+
`);
60+
61+
server.start({ port: 9000 });

examples/model.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
* npm run example:model
1414
*/
1515

16-
import { ModelClient, ResourceAlreadyExistError, ResourceNotExistError, Status, BackendType, ModelType, ModelService, ModelProxy } from '../src/index';
17-
import type { ModelServiceCreateInput, ModelServiceUpdateInput, ModelProxyCreateInput, ModelProxyUpdateInput, ProviderSettings, ProxyConfig } from '../src/index';
18-
import { logger } from '../src/utils/log';
16+
import type { ModelProxyCreateInput, ModelServiceCreateInput, ProviderSettings, ProxyConfig } from '../src/index';
17+
import { ModelClient, ModelProxy, ModelService, ModelType, ResourceAlreadyExistError, ResourceNotExistError, Status } from '../src/index';
1918
import { Config } from '../src/utils/config';
19+
import { logger } from '../src/utils/log';
2020

2121
// Logger helper
2222
function log(message: string, ...args: unknown[]) {
@@ -68,7 +68,7 @@ async function createOrGetModelService(): Promise<ModelService> {
6868

6969
// 等待就绪 / Wait for ready
7070
await ms.waitUntilReadyOrFailed({
71-
beforeCheck: (service: ModelService) =>
71+
callback: (service) =>
7272
log(` 当前状态 / Current status: ${service.status}`),
7373
});
7474

@@ -112,7 +112,11 @@ async function updateModelService(ms: ModelService): Promise<void> {
112112
async function listModelServices(): Promise<void> {
113113
log('枚举资源列表 / Listing resources');
114114

115-
const services = await ModelService.list({ modelType: ModelType.LLM });
115+
const services = await ModelService.list({
116+
input: {
117+
modelType: ModelType.LLM
118+
}
119+
});
116120
log(
117121
`共有 ${services.length} 个资源,分别为 / Total ${services.length} resources:`,
118122
services.map((s) => s.modelServiceName)
@@ -131,8 +135,10 @@ async function invokeModelService(ms: ModelService): Promise<void> {
131135
});
132136

133137
// 流式输出 / Stream output
134-
for await (const chunk of result.textStream) {
135-
process.stdout.write(chunk);
138+
if ('textStream' in result && result.textStream) {
139+
for await (const chunk of result.textStream) {
140+
process.stdout.write(chunk);
141+
}
136142
}
137143
logger.info(''); // 换行
138144
}
@@ -198,7 +204,7 @@ async function createOrGetModelProxy(): Promise<ModelProxy> {
198204

199205
// 等待就绪 / Wait for ready
200206
await mp.waitUntilReadyOrFailed({
201-
beforeCheck: (proxy: ModelProxy) =>
207+
callback: (proxy) =>
202208
log(` 当前状态 / Current status: ${proxy.status}`),
203209
});
204210

@@ -257,14 +263,16 @@ async function listModelProxies(): Promise<void> {
257263
async function invokeModelProxy(mp: ModelProxy): Promise<void> {
258264
log('调用模型代理进行推理 / Invoking model proxy for inference');
259265

260-
const result = await mp.completions({
266+
const result = await mp.completion({
261267
messages: [{ role: 'user', content: '你好,请介绍一下你自己' }],
262268
stream: true,
263269
});
264270

265271
// 流式输出 / Stream output
266-
for await (const chunk of result.textStream) {
267-
process.stdout.write(chunk);
272+
if ('textStream' in result && result.textStream) {
273+
for await (const chunk of result.textStream) {
274+
process.stdout.write(chunk);
275+
}
268276
}
269277
logger.info(''); // 换行
270278
}

package.json

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,58 @@
1111
"types": "./dist/index.d.ts",
1212
"import": "./dist/index.js",
1313
"require": "./dist/index.cjs"
14+
},
15+
"./agent-runtime": {
16+
"types": "./dist/agent-runtime/index.d.ts",
17+
"import": "./dist/agent-runtime/index.js",
18+
"require": "./dist/agent-runtime/index.cjs"
19+
},
20+
"./credential": {
21+
"types": "./dist/credential/index.d.ts",
22+
"import": "./dist/credential/index.js",
23+
"require": "./dist/credential/index.cjs"
24+
},
25+
"./integration": {
26+
"types": "./dist/integration/index.d.ts",
27+
"import": "./dist/integration/index.js",
28+
"require": "./dist/integration/index.cjs"
29+
},
30+
"./integration/mastra": {
31+
"types": "./dist/integration/mastra/index.d.ts",
32+
"import": "./dist/integration/mastra/index.js",
33+
"require": "./dist/integration/mastra/index.cjs"
34+
},
35+
"./model": {
36+
"types": "./dist/model/index.d.ts",
37+
"import": "./dist/model/index.js",
38+
"require": "./dist/model/index.cjs"
39+
},
40+
"./sandbox": {
41+
"types": "./dist/sandbox/index.d.ts",
42+
"import": "./dist/sandbox/index.js",
43+
"require": "./dist/sandbox/index.cjs"
44+
},
45+
"./server": {
46+
"types": "./dist/server/index.d.ts",
47+
"import": "./dist/server/index.js",
48+
"require": "./dist/server/index.cjs"
49+
},
50+
"./toolset": {
51+
"types": "./dist/toolset/index.d.ts",
52+
"import": "./dist/toolset/index.js",
53+
"require": "./dist/toolset/index.cjs"
1454
}
1555
},
1656
"files": [
1757
"dist",
1858
"README.md"
1959
],
2060
"scripts": {
61+
"prebuild": "npm run generate-exports",
2162
"build": "tsup",
2263
"build:types": "tsc -p tsconfig.types.json",
2364
"codegen": "npx tsx scripts/codegen.ts",
65+
"generate-exports": "node scripts/generate-exports.mjs",
2466
"format": "prettier --check \"src/**/*.{js,ts,jsx,tsx}\" --write",
2567
"test": "jest",
2668
"test:watch": "jest --watch",
@@ -30,6 +72,7 @@
3072
"typecheck": "tsc --noEmit",
3173
"prepublishOnly": "npm run build",
3274
"example:quick-start": "npx tsx examples/quick-start.ts",
75+
"example:quick-start-with-tools": "npx tsx examples/quick-start-with-tools.ts",
3376
"example:agent-runtime": "npx tsx examples/agent-runtime.ts",
3477
"example:credential": "npx tsx examples/credential.ts",
3578
"example:sandbox": "npx tsx examples/sandbox.ts"
@@ -72,8 +115,17 @@
72115
"uuid": "^9.0.0",
73116
"zod": "^4.2.1"
74117
},
118+
"peerDependencies": {
119+
"@mastra/core": "*"
120+
},
121+
"peerDependenciesMeta": {
122+
"@mastra/core": {
123+
"optional": true
124+
}
125+
},
75126
"devDependencies": {
76127
"@happy-dom/global-registrator": "^15.0.0",
128+
"@mastra/core": "^1.0.0",
77129
"@types/archiver": "^7.0.0",
78130
"@types/jest": "^29.5.0",
79131
"@types/js-yaml": "^4.0.9",
@@ -84,18 +136,11 @@
84136
"eslint": "^8.57.0",
85137
"jest": "^29.7.0",
86138
"jest-environment-node": "^29.7.0",
139+
"playwright": "^1.57.0",
87140
"ts-jest": "^29.2.0",
88141
"tsup": "^8.3.0",
89142
"tsx": "^4.19.0",
90143
"typescript": "^5.4.0",
91144
"yaml": "^2.7.0"
92-
},
93-
"peerDependencies": {
94-
"@mastra/core": ">=0.5.0"
95-
},
96-
"peerDependenciesMeta": {
97-
"@mastra/core": {
98-
"optional": true
99-
}
100145
}
101146
}

scripts/generate-exports.mjs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Auto-generate package.json exports for sub-modules
5+
*
6+
* This script automatically scans the src directory for index.ts files
7+
* and generates the corresponding exports in package.json
8+
*
9+
* Usage: node scripts/generate-exports.mjs
10+
*/
11+
12+
import { readdirSync, statSync, readFileSync, writeFileSync } from 'fs';
13+
import { join, resolve, dirname } from 'path';
14+
import { fileURLToPath } from 'url';
15+
16+
const __filename = fileURLToPath(import.meta.url);
17+
const __dirname = dirname(__filename);
18+
const projectRoot = resolve(__dirname, '..');
19+
const packageJsonPath = join(projectRoot, 'package.json');
20+
21+
// 扫描 src 目录下的所有 index.ts 文件
22+
function getSubModules(srcDir) {
23+
const modules = [];
24+
const basePath = resolve(srcDir);
25+
26+
function scanDir(dir, relativePath = '') {
27+
const items = readdirSync(dir);
28+
29+
for (const item of items) {
30+
const fullPath = join(dir, item);
31+
const stat = statSync(fullPath);
32+
33+
if (stat.isDirectory()) {
34+
// 检查是否有 index.ts 文件
35+
const indexPath = join(fullPath, 'index.ts');
36+
try {
37+
if (statSync(indexPath).isFile()) {
38+
const modulePath = relativePath ? `${relativePath}/${item}` : item;
39+
modules.push(modulePath);
40+
}
41+
} catch {
42+
// index.ts 不存在,继续递归扫描子目录
43+
}
44+
45+
// 递归扫描子目录
46+
const newRelativePath = relativePath ? `${relativePath}/${item}` : item;
47+
scanDir(fullPath, newRelativePath);
48+
}
49+
}
50+
}
51+
52+
// 扫描 src 目录
53+
scanDir(basePath);
54+
55+
// 过滤出用户可能想要导入的模块
56+
// 排除一些内部目录,如 api, builtin, adapter, core, protocol, utils
57+
const excludedDirs = ['api', 'builtin', 'adapter', 'core', 'protocol', 'utils'];
58+
const mainModules = modules.filter(module => {
59+
const parts = module.split('/');
60+
const lastPart = parts[parts.length - 1];
61+
return !excludedDirs.includes(lastPart);
62+
});
63+
64+
return mainModules;
65+
}
66+
67+
// 生成 exports 配置
68+
function generateExports(modules) {
69+
const exports = {
70+
'.': {
71+
types: './dist/index.d.ts',
72+
import: './dist/index.js',
73+
require: './dist/index.cjs'
74+
}
75+
};
76+
77+
for (const module of modules) {
78+
exports[`./${module}`] = {
79+
types: `./dist/${module}/index.d.ts`,
80+
import: `./dist/${module}/index.js`,
81+
require: `./dist/${module}/index.cjs`
82+
};
83+
}
84+
85+
return exports;
86+
}
87+
88+
// 更新 package.json
89+
function updatePackageJson() {
90+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
91+
const subModules = getSubModules('src');
92+
const newExports = generateExports(subModules);
93+
94+
console.log('Found sub-modules:');
95+
subModules.forEach(mod => console.log(` - ${mod}`));
96+
97+
packageJson.exports = newExports;
98+
99+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
100+
101+
console.log(`\nUpdated package.json exports with ${subModules.length} sub-modules`);
102+
}
103+
104+
// 主函数
105+
function main() {
106+
try {
107+
updatePackageJson();
108+
console.log('✅ Exports generation completed successfully');
109+
} catch (error) {
110+
console.error('❌ Error generating exports:', error);
111+
process.exit(1);
112+
}
113+
}
114+
115+
main();

0 commit comments

Comments
 (0)