@coze-arch/cli 0.0.14 → 0.0.15-alpha.a0f5b9
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/lib/__templates__/nextjs/scripts/prepare.sh +3 -0
- package/lib/__templates__/nuxt-vue/scripts/prepare.sh +3 -0
- package/lib/__templates__/pi-agent/.coze +10 -0
- package/lib/__templates__/pi-agent/AGENTS.md +140 -0
- package/lib/__templates__/pi-agent/README.md +172 -0
- package/lib/__templates__/pi-agent/_gitignore +3 -0
- package/lib/__templates__/pi-agent/_npmrc +23 -0
- package/lib/__templates__/pi-agent/docs/project-overview.md +356 -0
- package/lib/__templates__/pi-agent/docs/user/getting-started.md +47 -0
- package/lib/__templates__/pi-agent/package.json +60 -0
- package/lib/__templates__/pi-agent/pi-resources/SYSTEM.md +15 -0
- package/lib/__templates__/pi-agent/pi-resources/extensions/preference-memory/index.ts +355 -0
- package/lib/__templates__/pi-agent/pi-resources/extensions/test-ping.ts +19 -0
- package/lib/__templates__/pi-agent/pi-resources/prompts/test-prompt.md +11 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-asr/SKILL.md +36 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-asr/scripts/asr.mjs +9 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-image-gen/SKILL.md +41 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-image-gen/scripts/gen.mjs +9 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-tts/SKILL.md +85 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-tts/scripts/tts.mjs +9 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-video-gen/SKILL.md +53 -0
- package/lib/__templates__/pi-agent/pi-resources/skills/coze-video-gen/scripts/gen.mjs +9 -0
- package/lib/__templates__/pi-agent/pnpm-lock.yaml +8285 -0
- package/lib/__templates__/pi-agent/scripts/dev.sh +14 -0
- package/lib/__templates__/pi-agent/scripts/prepare.sh +2 -0
- package/lib/__templates__/pi-agent/src/agent.ts +363 -0
- package/lib/__templates__/pi-agent/src/channels/feishu/index.ts +760 -0
- package/lib/__templates__/pi-agent/src/channels/feishu/streaming-card.ts +297 -0
- package/lib/__templates__/pi-agent/src/channels/wechat/index.ts +171 -0
- package/lib/__templates__/pi-agent/src/config.ts +596 -0
- package/lib/__templates__/pi-agent/src/core.ts +218 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/channels.ts +148 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/docs.ts +204 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/models.ts +141 -0
- package/lib/__templates__/pi-agent/src/dashboard/api/overview.ts +33 -0
- package/lib/__templates__/pi-agent/src/dashboard/config-store.ts +64 -0
- package/lib/__templates__/pi-agent/src/dashboard/index.ts +39 -0
- package/lib/__templates__/pi-agent/src/dashboard/server.ts +622 -0
- package/lib/__templates__/pi-agent/src/dashboard/types.ts +25 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/index.html +13 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/postcss.config.cjs +7 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/app-layout.tsx +186 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/page-title.tsx +17 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/alert.tsx +22 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/badge.tsx +25 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/button.tsx +40 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/card.tsx +29 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/input.tsx +18 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/label.tsx +8 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/select.tsx +80 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/components/ui/separator.tsx +23 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/hooks/use-fetch.ts +32 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/hooks/use-local-storage-state.ts +23 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/main.tsx +30 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/channels-page.tsx +188 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/chat-page.tsx +451 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/docs-page.tsx +65 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/models-page.tsx +122 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/overview-page.tsx +134 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/services/chat-ws-service.ts +167 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/styles.css +294 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/src/utils/index.ts +11 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/tsconfig.json +13 -0
- package/lib/__templates__/pi-agent/src/dashboard/web/vite.config.ts +17 -0
- package/lib/__templates__/pi-agent/src/index.ts +123 -0
- package/lib/__templates__/pi-agent/src/pi-resources.ts +125 -0
- package/lib/__templates__/pi-agent/src/session-store.ts +223 -0
- package/lib/__templates__/pi-agent/src/tools/common/format-coze-error.ts +12 -0
- package/lib/__templates__/pi-agent/src/tools/index.ts +2 -0
- package/lib/__templates__/pi-agent/src/tools/web-fetch/index.ts +195 -0
- package/lib/__templates__/pi-agent/src/tools/web-search/index.ts +206 -0
- package/lib/__templates__/pi-agent/template.config.js +45 -0
- package/lib/__templates__/pi-agent/tests/config.test.ts +315 -0
- package/lib/__templates__/pi-agent/tests/dashboard-docs-api.test.ts +125 -0
- package/lib/__templates__/pi-agent/tests/dashboard-models-api.test.ts +171 -0
- package/lib/__templates__/pi-agent/tests/feishu-channel.test.ts +149 -0
- package/lib/__templates__/pi-agent/tests/feishu-streaming-card.test.ts +15 -0
- package/lib/__templates__/pi-agent/tests/pi-resources.test.ts +73 -0
- package/lib/__templates__/pi-agent/tests/preference-memory.test.ts +43 -0
- package/lib/__templates__/pi-agent/tests/session-store.test.ts +61 -0
- package/lib/__templates__/pi-agent/tests/smoke/run-smoke.ts +275 -0
- package/lib/__templates__/pi-agent/tests/web-fetch.test.ts +157 -0
- package/lib/__templates__/pi-agent/tests/web-search.test.ts +208 -0
- package/lib/__templates__/pi-agent/tsconfig.json +21 -0
- package/lib/__templates__/pi-agent/types/larksuiteoapi-node-sdk.d.ts +113 -0
- package/lib/__templates__/taro/pnpm-lock.yaml +24 -14
- package/lib/__templates__/taro/server/package.json +0 -2
- package/lib/__templates__/templates.json +24 -0
- package/lib/__templates__/vite/scripts/prepare.sh +3 -0
- package/lib/cli.js +106 -8
- package/package.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { FetchClient, type FetchResponse } from "coze-coding-dev-sdk";
|
|
4
|
+
import { cozeWebFetchTool } from "../src/tools/web-fetch/index.js";
|
|
5
|
+
|
|
6
|
+
function resultText(result: { content: { type: string; text?: string }[] }): string {
|
|
7
|
+
return result.content[0].text ?? "";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function makeFetchResponse(overrides: Partial<FetchResponse> = {}): FetchResponse {
|
|
11
|
+
return {
|
|
12
|
+
url: "https://example.com",
|
|
13
|
+
title: "Example Page",
|
|
14
|
+
content: [
|
|
15
|
+
{ type: "text", text: "Hello world" },
|
|
16
|
+
{ type: "link", text: "Link A", url: "https://a.com" },
|
|
17
|
+
{ type: "image", image: { display_url: "https://img.com/1.png", width: 640, height: 480 } },
|
|
18
|
+
],
|
|
19
|
+
...overrides,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
test("web-fetch: text format renders numbered items with links and images", async (t) => {
|
|
24
|
+
const resp = makeFetchResponse();
|
|
25
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => resp);
|
|
26
|
+
|
|
27
|
+
const result = await cozeWebFetchTool.execute("call-1", { urls: "https://example.com" }, undefined as any, undefined as any, undefined as any);
|
|
28
|
+
const text = resultText(result);
|
|
29
|
+
|
|
30
|
+
assert.ok(text.includes("1. Example Page"));
|
|
31
|
+
assert.ok(text.includes("URL: https://example.com"));
|
|
32
|
+
assert.ok(text.includes("Hello world"));
|
|
33
|
+
assert.ok(text.includes("Link A: https://a.com"));
|
|
34
|
+
assert.ok(text.includes("https://img.com/1.png (640x480)"));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("web-fetch: markdown format renders headings and markdown links", async (t) => {
|
|
38
|
+
const resp = makeFetchResponse();
|
|
39
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => resp);
|
|
40
|
+
|
|
41
|
+
const result = await cozeWebFetchTool.execute("call-2", { urls: ["https://example.com"], format: "markdown" }, undefined as any, undefined as any, undefined as any);
|
|
42
|
+
const text = resultText(result);
|
|
43
|
+
|
|
44
|
+
assert.ok(text.includes("# Example Page"));
|
|
45
|
+
assert.ok(text.includes("- [Link A](https://a.com)"));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("web-fetch: json format returns valid JSON", async (t) => {
|
|
49
|
+
const resp = makeFetchResponse();
|
|
50
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => resp);
|
|
51
|
+
|
|
52
|
+
const result = await cozeWebFetchTool.execute("call-3", { urls: "https://example.com", format: "json" }, undefined as any, undefined as any, undefined as any);
|
|
53
|
+
const parsed = JSON.parse(resultText(result));
|
|
54
|
+
|
|
55
|
+
assert.equal(Array.isArray(parsed), true);
|
|
56
|
+
assert.equal(parsed[0].url, "https://example.com");
|
|
57
|
+
assert.equal(parsed[0].title, "Example Page");
|
|
58
|
+
assert.equal(parsed[0].links.length, 1);
|
|
59
|
+
assert.equal(parsed[0].images.length, 1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("web-fetch: textOnly omits links and images", async (t) => {
|
|
63
|
+
const resp = makeFetchResponse();
|
|
64
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => resp);
|
|
65
|
+
|
|
66
|
+
const result = await cozeWebFetchTool.execute("call-4", { urls: "https://example.com", format: "json", textOnly: true }, undefined as any, undefined as any, undefined as any);
|
|
67
|
+
const parsed = JSON.parse(resultText(result));
|
|
68
|
+
|
|
69
|
+
assert.equal(parsed[0].links.length, 0);
|
|
70
|
+
assert.equal(parsed[0].images.length, 0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("web-fetch: filters out links with missing url", async (t) => {
|
|
74
|
+
const resp = makeFetchResponse({
|
|
75
|
+
content: [
|
|
76
|
+
{ type: "text", text: "body" },
|
|
77
|
+
{ type: "link", text: "Valid", url: "https://valid.com" },
|
|
78
|
+
{ type: "link", text: "Missing URL" },
|
|
79
|
+
{ type: "link", text: undefined, url: undefined },
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => resp);
|
|
83
|
+
|
|
84
|
+
const textResult = await cozeWebFetchTool.execute("call-5a", { urls: "https://example.com" }, undefined as any, undefined as any, undefined as any);
|
|
85
|
+
assert.ok(resultText(textResult).includes("Valid: https://valid.com"));
|
|
86
|
+
assert.ok(!resultText(textResult).includes("Missing URL"));
|
|
87
|
+
|
|
88
|
+
const mdResult = await cozeWebFetchTool.execute("call-5b", { urls: "https://example.com", format: "markdown" }, undefined as any, undefined as any, undefined as any);
|
|
89
|
+
assert.ok(resultText(mdResult).includes("[Valid](https://valid.com)"));
|
|
90
|
+
assert.ok(!resultText(mdResult).includes("Missing URL"));
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("web-fetch: image dimensions only shown when both width and height are numbers", async (t) => {
|
|
94
|
+
const resp = makeFetchResponse({
|
|
95
|
+
content: [
|
|
96
|
+
{ type: "text", text: "body" },
|
|
97
|
+
{ type: "image", image: { display_url: "https://img.com/a.png", width: 100, height: 200 } },
|
|
98
|
+
{ type: "image", image: { display_url: "https://img.com/b.png", width: 100 } },
|
|
99
|
+
{ type: "image", image: { display_url: "https://img.com/c.png" } },
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => resp);
|
|
103
|
+
|
|
104
|
+
const result = await cozeWebFetchTool.execute("call-6", { urls: "https://example.com" }, undefined as any, undefined as any, undefined as any);
|
|
105
|
+
const text = resultText(result);
|
|
106
|
+
|
|
107
|
+
assert.ok(text.includes("https://img.com/a.png (100x200)"));
|
|
108
|
+
assert.ok(text.includes("https://img.com/b.png"));
|
|
109
|
+
assert.ok(!text.includes("b.png (100x"));
|
|
110
|
+
assert.ok(text.includes("https://img.com/c.png"));
|
|
111
|
+
assert.ok(!text.includes("c.png ("));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("web-fetch: concurrent fetching preserves order", async (t) => {
|
|
115
|
+
const callOrder: number[] = [];
|
|
116
|
+
let callIndex = 0;
|
|
117
|
+
|
|
118
|
+
t.mock.method(FetchClient.prototype, "fetch", async (url: string) => {
|
|
119
|
+
const idx = callIndex++;
|
|
120
|
+
const delay = url.includes("slow") ? 50 : 10;
|
|
121
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
122
|
+
callOrder.push(idx);
|
|
123
|
+
return makeFetchResponse({ url, title: `Page ${idx}` });
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const urls = ["https://slow.com", "https://fast1.com", "https://fast2.com"];
|
|
127
|
+
const result = await cozeWebFetchTool.execute("call-7", { urls, format: "json" }, undefined as any, undefined as any, undefined as any);
|
|
128
|
+
const parsed = JSON.parse(resultText(result));
|
|
129
|
+
|
|
130
|
+
assert.equal(parsed.length, 3);
|
|
131
|
+
assert.equal(parsed[0].url, "https://slow.com");
|
|
132
|
+
assert.equal(parsed[1].url, "https://fast1.com");
|
|
133
|
+
assert.equal(parsed[2].url, "https://fast2.com");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("web-fetch: returns error content on fetch failure", async (t) => {
|
|
137
|
+
t.mock.method(FetchClient.prototype, "fetch", async () => {
|
|
138
|
+
throw new Error("Connection refused");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const result = await cozeWebFetchTool.execute("call-8", { urls: "https://example.com" }, undefined as any, undefined as any, undefined as any);
|
|
142
|
+
|
|
143
|
+
assert.ok(resultText(result).includes("Error: Connection refused"));
|
|
144
|
+
assert.equal((result as any).details.error, true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("web-fetch: single url string is normalized to array", async (t) => {
|
|
148
|
+
const calls: string[] = [];
|
|
149
|
+
t.mock.method(FetchClient.prototype, "fetch", async (url: string) => {
|
|
150
|
+
calls.push(url);
|
|
151
|
+
return makeFetchResponse({ url });
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await cozeWebFetchTool.execute("call-9", { urls: "https://single.com" }, undefined as any, undefined as any, undefined as any);
|
|
155
|
+
|
|
156
|
+
assert.deepEqual(calls, ["https://single.com"]);
|
|
157
|
+
});
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { SearchClient, type SearchResponse } from "coze-coding-dev-sdk";
|
|
4
|
+
import { cozeWebSearchTool } from "../src/tools/web-search/index.js";
|
|
5
|
+
|
|
6
|
+
function resultText(result: { content: { type: string; text?: string }[] }): string {
|
|
7
|
+
return result.content[0].text ?? "";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function makeWebSearchResponse(overrides: Partial<SearchResponse> = {}): SearchResponse {
|
|
11
|
+
return {
|
|
12
|
+
web_items: [
|
|
13
|
+
{
|
|
14
|
+
id: "1",
|
|
15
|
+
sort_id: 1,
|
|
16
|
+
title: "Result A",
|
|
17
|
+
site_name: "example.com",
|
|
18
|
+
url: "https://example.com/a",
|
|
19
|
+
snippet: "Snippet A",
|
|
20
|
+
auth_info_des: "",
|
|
21
|
+
auth_info_level: 0,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "2",
|
|
25
|
+
sort_id: 2,
|
|
26
|
+
title: "Result B",
|
|
27
|
+
url: "https://example.com/b",
|
|
28
|
+
snippet: "Snippet B",
|
|
29
|
+
publish_time: "2025-01-01",
|
|
30
|
+
auth_info_des: "",
|
|
31
|
+
auth_info_level: 0,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
image_items: [],
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function makeImageSearchResponse(): SearchResponse {
|
|
40
|
+
return {
|
|
41
|
+
web_items: [],
|
|
42
|
+
image_items: [
|
|
43
|
+
{
|
|
44
|
+
id: "img-1",
|
|
45
|
+
sort_id: 1,
|
|
46
|
+
title: "Cat Photo",
|
|
47
|
+
url: "https://example.com/cat",
|
|
48
|
+
site_name: "photos.com",
|
|
49
|
+
image: { url: "https://cdn.com/cat.jpg", width: 800, height: 600, shape: "rect" },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "img-2",
|
|
53
|
+
sort_id: 2,
|
|
54
|
+
url: "https://example.com/dog",
|
|
55
|
+
image: { url: "https://cdn.com/dog.jpg", width: 1024, height: 768, shape: "rect" },
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test("web-search: basic web search returns formatted text", async (t) => {
|
|
62
|
+
const resp = makeWebSearchResponse();
|
|
63
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => resp);
|
|
64
|
+
|
|
65
|
+
const result = await cozeWebSearchTool.execute("call-1", { query: "test" }, undefined as any, undefined as any, undefined as any);
|
|
66
|
+
const text = resultText(result);
|
|
67
|
+
|
|
68
|
+
assert.ok(text.includes("Coze web search: test"));
|
|
69
|
+
assert.ok(text.includes("Results (2)"));
|
|
70
|
+
assert.ok(text.includes("1. Result A"));
|
|
71
|
+
assert.ok(text.includes("URL: https://example.com/a"));
|
|
72
|
+
assert.ok(text.includes("Source: example.com"));
|
|
73
|
+
assert.ok(text.includes("Snippet A"));
|
|
74
|
+
assert.ok(text.includes("2. Result B"));
|
|
75
|
+
assert.ok(text.includes("Published: 2025-01-01"));
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("web-search: includes summary when present", async (t) => {
|
|
79
|
+
const resp = makeWebSearchResponse({ summary: "This is the summary" });
|
|
80
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => resp);
|
|
81
|
+
|
|
82
|
+
const result = await cozeWebSearchTool.execute("call-2", { query: "test", needSummary: true }, undefined as any, undefined as any, undefined as any);
|
|
83
|
+
const text = resultText(result);
|
|
84
|
+
|
|
85
|
+
assert.ok(text.includes("Summary: This is the summary"));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("web-search: includes content when needContent is true", async (t) => {
|
|
89
|
+
const resp = makeWebSearchResponse();
|
|
90
|
+
resp.web_items[0].content = "Full page content here";
|
|
91
|
+
t.mock.method(SearchClient.prototype, "advancedSearch", async () => resp);
|
|
92
|
+
|
|
93
|
+
const result = await cozeWebSearchTool.execute("call-3", { query: "test", needContent: true }, undefined as any, undefined as any, undefined as any);
|
|
94
|
+
const text = resultText(result);
|
|
95
|
+
|
|
96
|
+
assert.ok(text.includes("Content:"));
|
|
97
|
+
assert.ok(text.includes("Full page content here"));
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("web-search: image search maps image items", async (t) => {
|
|
101
|
+
const resp = makeImageSearchResponse();
|
|
102
|
+
t.mock.method(SearchClient.prototype, "imageSearch", async () => resp);
|
|
103
|
+
|
|
104
|
+
const result = await cozeWebSearchTool.execute("call-4", { query: "cats", type: "image" }, undefined as any, undefined as any, undefined as any);
|
|
105
|
+
const text = resultText(result);
|
|
106
|
+
|
|
107
|
+
assert.ok(text.includes("1. Cat Photo"));
|
|
108
|
+
assert.ok(text.includes("Image: https://cdn.com/cat.jpg"));
|
|
109
|
+
assert.ok(text.includes("2. Untitled"));
|
|
110
|
+
assert.ok(text.includes("Image: https://cdn.com/dog.jpg"));
|
|
111
|
+
assert.equal((result as any).details.type, "image");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("web-search: uses advancedSearch when filters are present", async (t) => {
|
|
115
|
+
const resp = makeWebSearchResponse();
|
|
116
|
+
const calls: string[] = [];
|
|
117
|
+
t.mock.method(SearchClient.prototype, "advancedSearch", async () => {
|
|
118
|
+
calls.push("advancedSearch");
|
|
119
|
+
return resp;
|
|
120
|
+
});
|
|
121
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => {
|
|
122
|
+
calls.push("webSearch");
|
|
123
|
+
return resp;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await cozeWebSearchTool.execute("call-5", { query: "test", timeRange: "1d" }, undefined as any, undefined as any, undefined as any);
|
|
127
|
+
assert.deepEqual(calls, ["advancedSearch"]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("web-search: uses webSearch when no filters present", async (t) => {
|
|
131
|
+
const resp = makeWebSearchResponse();
|
|
132
|
+
const calls: string[] = [];
|
|
133
|
+
t.mock.method(SearchClient.prototype, "advancedSearch", async () => {
|
|
134
|
+
calls.push("advancedSearch");
|
|
135
|
+
return resp;
|
|
136
|
+
});
|
|
137
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => {
|
|
138
|
+
calls.push("webSearch");
|
|
139
|
+
return resp;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await cozeWebSearchTool.execute("call-6", { query: "test" }, undefined as any, undefined as any, undefined as any);
|
|
143
|
+
assert.deepEqual(calls, ["webSearch"]);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("web-search: uses advancedSearch when sites filter is set", async (t) => {
|
|
147
|
+
const resp = makeWebSearchResponse();
|
|
148
|
+
const calls: string[] = [];
|
|
149
|
+
t.mock.method(SearchClient.prototype, "advancedSearch", async () => {
|
|
150
|
+
calls.push("advancedSearch");
|
|
151
|
+
return resp;
|
|
152
|
+
});
|
|
153
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => {
|
|
154
|
+
calls.push("webSearch");
|
|
155
|
+
return resp;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await cozeWebSearchTool.execute("call-7", { query: "test", sites: "example.com" }, undefined as any, undefined as any, undefined as any);
|
|
159
|
+
assert.deepEqual(calls, ["advancedSearch"]);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("web-search: returns error content on search failure", async (t) => {
|
|
163
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => {
|
|
164
|
+
throw new Error("API timeout");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const result = await cozeWebSearchTool.execute("call-8", { query: "test" }, undefined as any, undefined as any, undefined as any);
|
|
168
|
+
|
|
169
|
+
assert.ok(resultText(result).includes("Error: API timeout"));
|
|
170
|
+
assert.equal((result as any).details.error, true);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("web-search: defaults count to 10 and type to web", async (t) => {
|
|
174
|
+
const captured: any[] = [];
|
|
175
|
+
t.mock.method(SearchClient.prototype, "webSearch", async (query: string, count: number, needSummary?: boolean) => {
|
|
176
|
+
captured.push({ query, count, needSummary });
|
|
177
|
+
return makeWebSearchResponse();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
await cozeWebSearchTool.execute("call-9", { query: "hello" }, undefined as any, undefined as any, undefined as any);
|
|
181
|
+
|
|
182
|
+
assert.equal(captured[0].query, "hello");
|
|
183
|
+
assert.equal(captured[0].count, 10);
|
|
184
|
+
assert.equal((captured[0] as any).needSummary, undefined);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("web-search: details contain correct metadata", async (t) => {
|
|
188
|
+
const resp = makeWebSearchResponse({ summary: "Sum" });
|
|
189
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => resp);
|
|
190
|
+
|
|
191
|
+
const result = await cozeWebSearchTool.execute("call-10", { query: "meta test" }, undefined as any, undefined as any, undefined as any);
|
|
192
|
+
|
|
193
|
+
assert.equal((result as any).details.query, "meta test");
|
|
194
|
+
assert.equal((result as any).details.type, "web");
|
|
195
|
+
assert.equal((result as any).details.summary, "Sum");
|
|
196
|
+
assert.equal((result as any).details.count, 2);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("web-search: empty results produces correct output", async (t) => {
|
|
200
|
+
const resp: SearchResponse = { web_items: [], image_items: [] };
|
|
201
|
+
t.mock.method(SearchClient.prototype, "webSearch", async () => resp);
|
|
202
|
+
|
|
203
|
+
const result = await cozeWebSearchTool.execute("call-11", { query: "nothing" }, undefined as any, undefined as any, undefined as any);
|
|
204
|
+
const text = resultText(result);
|
|
205
|
+
|
|
206
|
+
assert.ok(text.includes("Results (0)"));
|
|
207
|
+
assert.equal((result as any).details.count, 0);
|
|
208
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"verbatimModuleSyntax": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"baseUrl": "."
|
|
14
|
+
},
|
|
15
|
+
"include": [
|
|
16
|
+
"src/**/*.ts",
|
|
17
|
+
"pi-resources/extensions/**/*.ts",
|
|
18
|
+
"tests/**/*.ts",
|
|
19
|
+
"types/**/*.d.ts"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
declare module "@larksuiteoapi/node-sdk" {
|
|
2
|
+
export enum AppType {
|
|
3
|
+
SelfBuild = "SelfBuild"
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export enum Domain {
|
|
7
|
+
Feishu = "https://open.feishu.cn",
|
|
8
|
+
Lark = "https://open.larksuite.com"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export enum LoggerLevel {
|
|
12
|
+
warn = "warn"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ClientOptions {
|
|
16
|
+
appId: string;
|
|
17
|
+
appSecret: string;
|
|
18
|
+
appType: AppType;
|
|
19
|
+
domain?: Domain | string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MessageReplyArgs {
|
|
23
|
+
path: {
|
|
24
|
+
message_id: string;
|
|
25
|
+
};
|
|
26
|
+
data: {
|
|
27
|
+
msg_type: string;
|
|
28
|
+
content: string;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface MessageReactionCreateArgs {
|
|
33
|
+
path: {
|
|
34
|
+
message_id: string;
|
|
35
|
+
};
|
|
36
|
+
data: {
|
|
37
|
+
reaction_type: {
|
|
38
|
+
emoji_type: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface MessageReactionDeleteArgs {
|
|
44
|
+
path: {
|
|
45
|
+
message_id: string;
|
|
46
|
+
reaction_id: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class Client {
|
|
51
|
+
constructor(options: ClientOptions);
|
|
52
|
+
request(args: {
|
|
53
|
+
method: string;
|
|
54
|
+
url: string;
|
|
55
|
+
data: Record<string, never>;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
bot?: {
|
|
58
|
+
open_id?: string;
|
|
59
|
+
};
|
|
60
|
+
data?: {
|
|
61
|
+
bot?: {
|
|
62
|
+
open_id?: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
}>;
|
|
66
|
+
im: {
|
|
67
|
+
message: {
|
|
68
|
+
reply(args: MessageReplyArgs): Promise<unknown>;
|
|
69
|
+
};
|
|
70
|
+
messageReaction: {
|
|
71
|
+
create(args: MessageReactionCreateArgs): Promise<{
|
|
72
|
+
code?: number;
|
|
73
|
+
msg?: string;
|
|
74
|
+
data?: {
|
|
75
|
+
reaction_id?: string;
|
|
76
|
+
reaction_type?: {
|
|
77
|
+
emoji_type?: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
}>;
|
|
81
|
+
delete(args: MessageReactionDeleteArgs): Promise<{
|
|
82
|
+
code?: number;
|
|
83
|
+
msg?: string;
|
|
84
|
+
data?: {
|
|
85
|
+
reaction_id?: string;
|
|
86
|
+
reaction_type?: {
|
|
87
|
+
emoji_type?: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
}>;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class EventDispatcher {
|
|
96
|
+
constructor(options: {
|
|
97
|
+
encryptKey: string;
|
|
98
|
+
verificationToken: string;
|
|
99
|
+
});
|
|
100
|
+
register(handlers: Record<string, (data: unknown) => Promise<void> | void>): void;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export class WSClient {
|
|
104
|
+
constructor(options: {
|
|
105
|
+
appId: string;
|
|
106
|
+
appSecret: string;
|
|
107
|
+
domain?: Domain | string;
|
|
108
|
+
loggerLevel?: LoggerLevel;
|
|
109
|
+
});
|
|
110
|
+
start(args: { eventDispatcher: EventDispatcher }): Promise<void>;
|
|
111
|
+
close(args?: { force?: boolean }): void;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -197,9 +197,6 @@ importers:
|
|
|
197
197
|
'@supabase/supabase-js':
|
|
198
198
|
specifier: 2.95.3
|
|
199
199
|
version: 2.95.3
|
|
200
|
-
better-sqlite3:
|
|
201
|
-
specifier: ^11.9.1
|
|
202
|
-
version: 11.10.0
|
|
203
200
|
coze-coding-dev-sdk:
|
|
204
201
|
specifier: ^0.7.16
|
|
205
202
|
version: 0.7.16(openai@6.16.0(ws@8.19.0)(zod@4.3.5))(ws@8.19.0)
|
|
@@ -234,9 +231,6 @@ importers:
|
|
|
234
231
|
'@nestjs/schematics':
|
|
235
232
|
specifier: ^10.2.3
|
|
236
233
|
version: 10.2.3(chokidar@3.6.0)(typescript@5.9.3)
|
|
237
|
-
'@types/better-sqlite3':
|
|
238
|
-
specifier: ^7.6.13
|
|
239
|
-
version: 7.6.13
|
|
240
234
|
'@types/express':
|
|
241
235
|
specifier: 5.0.6
|
|
242
236
|
version: 5.0.6
|
|
@@ -15586,6 +15580,7 @@ snapshots:
|
|
|
15586
15580
|
'@types/better-sqlite3@7.6.13':
|
|
15587
15581
|
dependencies:
|
|
15588
15582
|
'@types/node': 22.19.6
|
|
15583
|
+
optional: true
|
|
15589
15584
|
|
|
15590
15585
|
'@types/body-parser@1.19.6':
|
|
15591
15586
|
dependencies:
|
|
@@ -16921,6 +16916,7 @@ snapshots:
|
|
|
16921
16916
|
dependencies:
|
|
16922
16917
|
bindings: 1.5.0
|
|
16923
16918
|
prebuild-install: 7.1.3
|
|
16919
|
+
optional: true
|
|
16924
16920
|
|
|
16925
16921
|
big-integer@1.6.52: {}
|
|
16926
16922
|
|
|
@@ -16936,6 +16932,7 @@ snapshots:
|
|
|
16936
16932
|
bindings@1.5.0:
|
|
16937
16933
|
dependencies:
|
|
16938
16934
|
file-uri-to-path: 1.0.0
|
|
16935
|
+
optional: true
|
|
16939
16936
|
|
|
16940
16937
|
bl@1.2.3:
|
|
16941
16938
|
dependencies:
|
|
@@ -17239,7 +17236,8 @@ snapshots:
|
|
|
17239
17236
|
dependencies:
|
|
17240
17237
|
readdirp: 5.0.0
|
|
17241
17238
|
|
|
17242
|
-
chownr@1.1.4:
|
|
17239
|
+
chownr@1.1.4:
|
|
17240
|
+
optional: true
|
|
17243
17241
|
|
|
17244
17242
|
chroma-js@2.6.0: {}
|
|
17245
17243
|
|
|
@@ -17735,6 +17733,7 @@ snapshots:
|
|
|
17735
17733
|
decompress-response@6.0.0:
|
|
17736
17734
|
dependencies:
|
|
17737
17735
|
mimic-response: 3.1.0
|
|
17736
|
+
optional: true
|
|
17738
17737
|
|
|
17739
17738
|
decompress-tar@4.1.1:
|
|
17740
17739
|
dependencies:
|
|
@@ -18491,7 +18490,8 @@ snapshots:
|
|
|
18491
18490
|
|
|
18492
18491
|
exif-parser@0.1.12: {}
|
|
18493
18492
|
|
|
18494
|
-
expand-template@2.0.3:
|
|
18493
|
+
expand-template@2.0.3:
|
|
18494
|
+
optional: true
|
|
18495
18495
|
|
|
18496
18496
|
express@4.21.2:
|
|
18497
18497
|
dependencies:
|
|
@@ -18679,7 +18679,8 @@ snapshots:
|
|
|
18679
18679
|
|
|
18680
18680
|
file-type@8.1.0: {}
|
|
18681
18681
|
|
|
18682
|
-
file-uri-to-path@1.0.0:
|
|
18682
|
+
file-uri-to-path@1.0.0:
|
|
18683
|
+
optional: true
|
|
18683
18684
|
|
|
18684
18685
|
filename-reserved-regex@2.0.0: {}
|
|
18685
18686
|
|
|
@@ -18963,7 +18964,8 @@ snapshots:
|
|
|
18963
18964
|
|
|
18964
18965
|
git-clone@0.1.0: {}
|
|
18965
18966
|
|
|
18966
|
-
github-from-package@0.0.0:
|
|
18967
|
+
github-from-package@0.0.0:
|
|
18968
|
+
optional: true
|
|
18967
18969
|
|
|
18968
18970
|
glob-parent@5.1.2:
|
|
18969
18971
|
dependencies:
|
|
@@ -20214,7 +20216,8 @@ snapshots:
|
|
|
20214
20216
|
|
|
20215
20217
|
mimic-response@1.0.1: {}
|
|
20216
20218
|
|
|
20217
|
-
mimic-response@3.1.0:
|
|
20219
|
+
mimic-response@3.1.0:
|
|
20220
|
+
optional: true
|
|
20218
20221
|
|
|
20219
20222
|
min-document@2.19.2:
|
|
20220
20223
|
dependencies:
|
|
@@ -20446,7 +20449,8 @@ snapshots:
|
|
|
20446
20449
|
|
|
20447
20450
|
mkdir-p@0.0.7: {}
|
|
20448
20451
|
|
|
20449
|
-
mkdirp-classic@0.5.3:
|
|
20452
|
+
mkdirp-classic@0.5.3:
|
|
20453
|
+
optional: true
|
|
20450
20454
|
|
|
20451
20455
|
mkdirp@0.5.6:
|
|
20452
20456
|
dependencies:
|
|
@@ -20503,7 +20507,8 @@ snapshots:
|
|
|
20503
20507
|
|
|
20504
20508
|
nanoid@3.3.11: {}
|
|
20505
20509
|
|
|
20506
|
-
napi-build-utils@2.0.0:
|
|
20510
|
+
napi-build-utils@2.0.0:
|
|
20511
|
+
optional: true
|
|
20507
20512
|
|
|
20508
20513
|
natural-compare@1.4.0: {}
|
|
20509
20514
|
|
|
@@ -20545,6 +20550,7 @@ snapshots:
|
|
|
20545
20550
|
node-abi@3.87.0:
|
|
20546
20551
|
dependencies:
|
|
20547
20552
|
semver: 7.7.4
|
|
20553
|
+
optional: true
|
|
20548
20554
|
|
|
20549
20555
|
node-abort-controller@3.1.1: {}
|
|
20550
20556
|
|
|
@@ -21505,6 +21511,7 @@ snapshots:
|
|
|
21505
21511
|
simple-get: 4.0.1
|
|
21506
21512
|
tar-fs: 2.1.4
|
|
21507
21513
|
tunnel-agent: 0.6.0
|
|
21514
|
+
optional: true
|
|
21508
21515
|
|
|
21509
21516
|
prelude-ls@1.2.1: {}
|
|
21510
21517
|
|
|
@@ -22232,13 +22239,15 @@ snapshots:
|
|
|
22232
22239
|
|
|
22233
22240
|
signal-exit@4.1.0: {}
|
|
22234
22241
|
|
|
22235
|
-
simple-concat@1.0.1:
|
|
22242
|
+
simple-concat@1.0.1:
|
|
22243
|
+
optional: true
|
|
22236
22244
|
|
|
22237
22245
|
simple-get@4.0.1:
|
|
22238
22246
|
dependencies:
|
|
22239
22247
|
decompress-response: 6.0.0
|
|
22240
22248
|
once: 1.4.0
|
|
22241
22249
|
simple-concat: 1.0.1
|
|
22250
|
+
optional: true
|
|
22242
22251
|
|
|
22243
22252
|
simple-plist@1.3.1:
|
|
22244
22253
|
dependencies:
|
|
@@ -22650,6 +22659,7 @@ snapshots:
|
|
|
22650
22659
|
mkdirp-classic: 0.5.3
|
|
22651
22660
|
pump: 3.0.3
|
|
22652
22661
|
tar-stream: 2.2.0
|
|
22662
|
+
optional: true
|
|
22653
22663
|
|
|
22654
22664
|
tar-stream@1.6.2:
|
|
22655
22665
|
dependencies:
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"@nestjs/core": "^10.4.15",
|
|
18
18
|
"@nestjs/platform-express": "^10.4.15",
|
|
19
19
|
"@supabase/supabase-js": "2.95.3",
|
|
20
|
-
"better-sqlite3": "^11.9.1",
|
|
21
20
|
"coze-coding-dev-sdk": "^0.7.16",
|
|
22
21
|
"dotenv": "^17.2.3",
|
|
23
22
|
"drizzle-kit": "^0.31.8",
|
|
@@ -31,7 +30,6 @@
|
|
|
31
30
|
"devDependencies": {
|
|
32
31
|
"@nestjs/cli": "^10.4.9",
|
|
33
32
|
"@nestjs/schematics": "^10.2.3",
|
|
34
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
35
33
|
"@types/express": "5.0.6",
|
|
36
34
|
"@types/node": "^22.10.2",
|
|
37
35
|
"drizzle-kit": "^0.31.8",
|