gaoding-cli 1.0.0-alpha.13 → 1.0.0-alpha.15
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 +2 -2
- package/contracts/operations/agent.send/input.schema.json +4 -0
- package/contracts/operations/model.get/output.schema.json +1 -0
- package/dist/bin/gd-cli.js +37 -16
- package/dist/src/bootstrap/create-cli.js +43 -4
- package/dist/src/bootstrap/create-runtime.js +44 -13
- package/dist/src/cli/action-binding.js +43 -9
- package/dist/src/cli/agent-commands.js +13 -3
- package/dist/src/cli/auth-commands.js +21 -13
- package/dist/src/cli/dam-commands.js +35 -20
- package/dist/src/cli/errors.js +34 -1
- package/dist/src/cli/model-commands.js +25 -11
- package/dist/src/cli/org-commands.js +18 -12
- package/dist/src/cli/presenter.js +11 -1
- package/dist/src/cli/tool-commands.js +19 -7
- package/dist/src/cli/update-command.js +6 -4
- package/dist/src/features/agent/creative-agent-adapter.js +19 -14
- package/dist/src/features/agent/creative-protocol.js +7 -3
- package/dist/src/features/agent/use-cases.js +63 -54
- package/dist/src/features/auth/use-cases.js +82 -65
- package/dist/src/features/dam/asset-projection.js +22 -14
- package/dist/src/features/dam/dam-api-adapter.js +19 -4
- package/dist/src/features/dam/object-storage.js +2 -0
- package/dist/src/features/dam/registered-uploader.js +58 -35
- package/dist/src/features/dam/use-cases.js +39 -32
- package/dist/src/features/org/use-cases.js +27 -11
- package/dist/src/features/tool/catalog.js +7 -3
- package/dist/src/features/tool/dynamic-schema.js +19 -9
- package/dist/src/features/tool/mns-catalog-adapter.js +7 -4
- package/dist/src/features/tool/tool-api-adapter.js +186 -73
- package/dist/src/features/tool/use-cases.js +63 -34
- package/dist/src/features/update/update-service.js +28 -22
- package/dist/src/platform/json-input.js +3 -0
- package/dist/src/platform/remote-error-evidence.js +66 -0
- package/dist/src/platform/remote-protocol.js +10 -0
- package/dist/src/platform/signed-http-transport.js +31 -5
- package/dist/src/telemetry/invocation.js +156 -0
- package/dist/src/telemetry/sls-sink.js +31 -0
- package/package.json +1 -1
- package/skills/gd-cli/references/creation.md +15 -4
- package/skills/gd-cli/references/errors.md +3 -1
|
@@ -11,6 +11,8 @@ function parameterSchema(parameter) {
|
|
|
11
11
|
if (parameter.type === "uri[]") {
|
|
12
12
|
return { type: "array", items: { type: "string", format: "uri" }, ...common };
|
|
13
13
|
}
|
|
14
|
+
if (parameter.type === "number")
|
|
15
|
+
return { type: "number", ...common };
|
|
14
16
|
return {
|
|
15
17
|
type: "string",
|
|
16
18
|
...(parameter.options === undefined
|
|
@@ -67,29 +69,37 @@ export function buildToolArgumentsSchema(catalog, tool) {
|
|
|
67
69
|
additionalProperties: false
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
|
-
|
|
71
|
-
const addFormats = addFormatsImport;
|
|
72
|
-
addFormats(ajv);
|
|
73
|
-
function validator(model) {
|
|
72
|
+
export function buildModelArgumentsSchema(model) {
|
|
74
73
|
const properties = {
|
|
75
|
-
model: {
|
|
74
|
+
model: {
|
|
75
|
+
type: "string",
|
|
76
|
+
const: model.model,
|
|
77
|
+
description: "要调用的模型机器标识。"
|
|
78
|
+
}
|
|
76
79
|
};
|
|
77
80
|
for (const parameter of model.parameters) {
|
|
78
81
|
properties[parameter.name] = parameterSchema(parameter);
|
|
79
82
|
}
|
|
80
|
-
return
|
|
83
|
+
return {
|
|
81
84
|
type: "object",
|
|
82
85
|
properties,
|
|
83
86
|
required: [
|
|
84
87
|
"model",
|
|
85
|
-
...model.parameters
|
|
88
|
+
...model.parameters
|
|
89
|
+
.filter((parameter) => parameter.required)
|
|
90
|
+
.map((parameter) => parameter.name)
|
|
86
91
|
],
|
|
87
92
|
additionalProperties: false
|
|
88
|
-
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const ajv = new Ajv2020({ allErrors: true, strict: true });
|
|
96
|
+
const addFormats = addFormatsImport;
|
|
97
|
+
addFormats(ajv);
|
|
98
|
+
function validator(model) {
|
|
99
|
+
return ajv.compile(buildModelArgumentsSchema(model));
|
|
89
100
|
}
|
|
90
101
|
export function assertModelArguments(model, value) {
|
|
91
102
|
if (typeof value !== "object" || value === null
|
|
92
|
-
|| value.model !== model.model
|
|
93
103
|
|| !validator(model)(value)) {
|
|
94
104
|
throw new ToolInputError();
|
|
95
105
|
}
|
|
@@ -18,6 +18,7 @@ const toolOrder = {
|
|
|
18
18
|
};
|
|
19
19
|
const multiUriKeys = new Set([
|
|
20
20
|
"image_urls",
|
|
21
|
+
"reference_images",
|
|
21
22
|
"file_urls",
|
|
22
23
|
"video_urls",
|
|
23
24
|
"audio_urls"
|
|
@@ -98,9 +99,11 @@ function parameter(value) {
|
|
|
98
99
|
? "uri[]"
|
|
99
100
|
: name === "start_frame" || name === "end_frame" || sourceType === "IMAGE"
|
|
100
101
|
? "uri"
|
|
101
|
-
: sourceType === "
|
|
102
|
-
? "
|
|
103
|
-
:
|
|
102
|
+
: sourceType === "NUMBER"
|
|
103
|
+
? "number"
|
|
104
|
+
: sourceType === "TEXT" || sourceType === "INPUT" || sourceType === "SELECT"
|
|
105
|
+
? "string"
|
|
106
|
+
: undefined;
|
|
104
107
|
if (type === undefined)
|
|
105
108
|
throw new Error("unsupported parameter");
|
|
106
109
|
let options;
|
|
@@ -120,7 +123,7 @@ function parameter(value) {
|
|
|
120
123
|
if (options.length === 0)
|
|
121
124
|
throw new Error("empty options");
|
|
122
125
|
}
|
|
123
|
-
const description = text(field.
|
|
126
|
+
const description = text(field.description) ?? text(field.label);
|
|
124
127
|
const defaultValue = field.default_value;
|
|
125
128
|
const hasDefault = defaultValue !== undefined
|
|
126
129
|
&& defaultValue !== null
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { randomInt } from "node:crypto";
|
|
2
2
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3
3
|
import { RemoteRequestError } from "../../platform/signed-http-transport.js";
|
|
4
|
+
import { remoteErrorEvidence } from "../../platform/remote-error-evidence.js";
|
|
5
|
+
import { RemoteProtocolError } from "../../platform/remote-protocol.js";
|
|
4
6
|
const MAX_JAVA_LONG = 9223372036854775807n;
|
|
5
7
|
function isRecord(value) {
|
|
6
8
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -8,6 +10,9 @@ function isRecord(value) {
|
|
|
8
10
|
function fail() {
|
|
9
11
|
throw new RemoteRequestError();
|
|
10
12
|
}
|
|
13
|
+
function protocolFailure(value) {
|
|
14
|
+
throw new RemoteProtocolError(remoteErrorEvidence(value));
|
|
15
|
+
}
|
|
11
16
|
function nonBlank(value) {
|
|
12
17
|
if (typeof value !== "string" || value.trim() === "")
|
|
13
18
|
return fail();
|
|
@@ -43,9 +48,17 @@ function parseIntent(value) {
|
|
|
43
48
|
};
|
|
44
49
|
}
|
|
45
50
|
function submittedTask(value) {
|
|
46
|
-
if (!isRecord(value) || !isRecord(value.result)
|
|
47
|
-
return
|
|
48
|
-
|
|
51
|
+
if (!isRecord(value) || !isRecord(value.result))
|
|
52
|
+
return protocolFailure(value);
|
|
53
|
+
if (value.result.isError === true) {
|
|
54
|
+
throw new ToolTaskFailedError(remoteErrorEvidence(value));
|
|
55
|
+
}
|
|
56
|
+
if (value.result.isError !== false)
|
|
57
|
+
return protocolFailure(value);
|
|
58
|
+
if (typeof value.task_id !== "string" || value.task_id.trim() === "") {
|
|
59
|
+
return protocolFailure(value);
|
|
60
|
+
}
|
|
61
|
+
return value.task_id;
|
|
49
62
|
}
|
|
50
63
|
function resourceName(uri) {
|
|
51
64
|
let url;
|
|
@@ -53,32 +66,42 @@ function resourceName(uri) {
|
|
|
53
66
|
url = new URL(uri);
|
|
54
67
|
}
|
|
55
68
|
catch {
|
|
56
|
-
return
|
|
69
|
+
return protocolFailure(uri);
|
|
57
70
|
}
|
|
58
71
|
const segment = url.pathname.split("/").filter(Boolean).at(-1);
|
|
59
72
|
if (segment === undefined)
|
|
60
|
-
return
|
|
73
|
+
return protocolFailure(uri);
|
|
61
74
|
try {
|
|
62
|
-
|
|
75
|
+
const decoded = decodeURIComponent(segment);
|
|
76
|
+
if (decoded.trim() === "")
|
|
77
|
+
return protocolFailure(uri);
|
|
78
|
+
return decoded;
|
|
63
79
|
}
|
|
64
80
|
catch {
|
|
65
|
-
return
|
|
81
|
+
return protocolFailure(uri);
|
|
66
82
|
}
|
|
67
83
|
}
|
|
68
84
|
function normalizeContent(value) {
|
|
69
85
|
if (!isRecord(value))
|
|
70
|
-
return
|
|
86
|
+
return protocolFailure(value);
|
|
71
87
|
if (value.type === "text") {
|
|
72
|
-
|
|
88
|
+
if (typeof value.text !== "string" || value.text.trim() === "") {
|
|
89
|
+
return protocolFailure(value);
|
|
90
|
+
}
|
|
91
|
+
return { type: "text", text: value.text };
|
|
92
|
+
}
|
|
93
|
+
if (value.type !== "resource" || !isRecord(value.resource)) {
|
|
94
|
+
return protocolFailure(value);
|
|
73
95
|
}
|
|
74
|
-
if (value.type !== "resource" || !isRecord(value.resource))
|
|
75
|
-
return fail();
|
|
76
96
|
if ("blob" in value.resource || "text" in value.resource)
|
|
77
|
-
return
|
|
78
|
-
|
|
97
|
+
return protocolFailure(value);
|
|
98
|
+
if (typeof value.resource.uri !== "string" || value.resource.uri.trim() === "") {
|
|
99
|
+
return protocolFailure(value);
|
|
100
|
+
}
|
|
101
|
+
const uri = value.resource.uri;
|
|
79
102
|
const mimeType = value.resource.mimeType;
|
|
80
103
|
if (mimeType !== undefined && (typeof mimeType !== "string" || mimeType.trim() === "")) {
|
|
81
|
-
return
|
|
104
|
+
return protocolFailure(value);
|
|
82
105
|
}
|
|
83
106
|
return {
|
|
84
107
|
type: "resource_link",
|
|
@@ -87,23 +110,102 @@ function normalizeContent(value) {
|
|
|
87
110
|
...(mimeType === undefined ? {} : { mimeType })
|
|
88
111
|
};
|
|
89
112
|
}
|
|
113
|
+
export class ToolTaskFailedError extends Error {
|
|
114
|
+
remoteCode;
|
|
115
|
+
remoteBody;
|
|
116
|
+
constructor(evidence = {}) {
|
|
117
|
+
super("稿定工具任务执行失败。");
|
|
118
|
+
this.name = "ToolTaskFailedError";
|
|
119
|
+
this.remoteCode = evidence.remoteCode;
|
|
120
|
+
this.remoteBody = evidence.remoteBody;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function failedPoll(error, difyTaskId) {
|
|
124
|
+
return {
|
|
125
|
+
state: "failed",
|
|
126
|
+
error,
|
|
127
|
+
...(difyTaskId === undefined ? {} : { difyTaskId })
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function optionalInnerDifyTaskId(value) {
|
|
131
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
132
|
+
return undefined;
|
|
133
|
+
try {
|
|
134
|
+
const parsed = JSON.parse(value);
|
|
135
|
+
if (!isRecord(parsed))
|
|
136
|
+
return undefined;
|
|
137
|
+
const difyTaskId = parsed.dify_task_id;
|
|
138
|
+
return typeof difyTaskId === "string" && difyTaskId.trim() !== ""
|
|
139
|
+
? difyTaskId
|
|
140
|
+
: undefined;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
90
146
|
function pollResult(value, taskId) {
|
|
91
147
|
if (!Array.isArray(value))
|
|
92
|
-
return
|
|
148
|
+
return protocolFailure(value);
|
|
93
149
|
const item = value.find((candidate) => isRecord(candidate) && candidate.task_id === taskId);
|
|
94
|
-
if (!isRecord(item)
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
150
|
+
if (!isRecord(item))
|
|
151
|
+
return { state: "pending" };
|
|
152
|
+
if (typeof item.code !== "string" || item.code.trim() === "") {
|
|
153
|
+
return protocolFailure(item);
|
|
154
|
+
}
|
|
155
|
+
if (item.code !== "200") {
|
|
156
|
+
return failedPoll(new ToolTaskFailedError(remoteErrorEvidence(item)), optionalInnerDifyTaskId(item.result));
|
|
157
|
+
}
|
|
158
|
+
if (typeof item.result !== "string" || item.result.trim() === "") {
|
|
159
|
+
return protocolFailure(item);
|
|
160
|
+
}
|
|
161
|
+
let inner;
|
|
162
|
+
try {
|
|
163
|
+
const parsed = JSON.parse(item.result);
|
|
164
|
+
if (!isRecord(parsed))
|
|
165
|
+
return protocolFailure(item);
|
|
166
|
+
inner = parsed;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
if (error instanceof RemoteProtocolError)
|
|
170
|
+
throw error;
|
|
171
|
+
return protocolFailure(item);
|
|
172
|
+
}
|
|
173
|
+
const difyTaskId = inner.dify_task_id;
|
|
174
|
+
if (difyTaskId !== undefined
|
|
175
|
+
&& (typeof difyTaskId !== "string" || difyTaskId.trim() === "")) {
|
|
176
|
+
return protocolFailure(inner);
|
|
177
|
+
}
|
|
178
|
+
if (!isRecord(inner.result)) {
|
|
179
|
+
return failedPoll(new RemoteProtocolError(remoteErrorEvidence(inner)), difyTaskId);
|
|
180
|
+
}
|
|
181
|
+
if (inner.result.isError === true) {
|
|
182
|
+
return failedPoll(new ToolTaskFailedError(remoteErrorEvidence(inner)), difyTaskId);
|
|
183
|
+
}
|
|
184
|
+
if (inner.result.isError !== false) {
|
|
185
|
+
return failedPoll(new RemoteProtocolError(remoteErrorEvidence(inner)), difyTaskId);
|
|
186
|
+
}
|
|
99
187
|
const content = inner.result.content;
|
|
100
|
-
if (content === undefined)
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
188
|
+
if (content === undefined || (Array.isArray(content) && content.length === 0)) {
|
|
189
|
+
return {
|
|
190
|
+
state: "pending",
|
|
191
|
+
...(difyTaskId === undefined ? {} : { difyTaskId })
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (!Array.isArray(content)) {
|
|
195
|
+
return failedPoll(new RemoteProtocolError(remoteErrorEvidence(inner)), difyTaskId);
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
return {
|
|
199
|
+
state: "complete",
|
|
200
|
+
content: content.map(normalizeContent),
|
|
201
|
+
...(difyTaskId === undefined ? {} : { difyTaskId })
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
if (error instanceof RemoteProtocolError)
|
|
206
|
+
return failedPoll(error, difyTaskId);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
107
209
|
}
|
|
108
210
|
async function safePost(transport, request) {
|
|
109
211
|
try {
|
|
@@ -112,7 +214,7 @@ async function safePost(transport, request) {
|
|
|
112
214
|
catch (error) {
|
|
113
215
|
if (request.signal.aborted)
|
|
114
216
|
throw request.signal.reason;
|
|
115
|
-
if (error instanceof RemoteRequestError)
|
|
217
|
+
if (error instanceof RemoteRequestError || error instanceof RemoteProtocolError)
|
|
116
218
|
throw error;
|
|
117
219
|
throw new RemoteRequestError();
|
|
118
220
|
}
|
|
@@ -138,7 +240,7 @@ export function createToolApiAdapter(dependencies) {
|
|
|
138
240
|
async execute({ invocation, access, signal }) {
|
|
139
241
|
signal.throwIfAborted();
|
|
140
242
|
const managedContentId = contentId(createContentId());
|
|
141
|
-
const intent = parseIntent(await safePost(dependencies.transport, {
|
|
243
|
+
const intent = await dependencies.telemetry.stage("intent", async () => parseIntent(await safePost(dependencies.transport, {
|
|
142
244
|
path: "/ai-agent/v1/tool-intent",
|
|
143
245
|
body: {
|
|
144
246
|
prompt: invocation.prompt,
|
|
@@ -148,53 +250,64 @@ export function createToolApiAdapter(dependencies) {
|
|
|
148
250
|
credential: access.credential,
|
|
149
251
|
organizationId: access.organizationId,
|
|
150
252
|
signal
|
|
151
|
-
}));
|
|
253
|
+
})));
|
|
152
254
|
signal.throwIfAborted();
|
|
153
|
-
const taskId =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
255
|
+
const taskId = await dependencies.telemetry.stage("submit", async () => {
|
|
256
|
+
dependencies.telemetry.annotate({ content_id: managedContentId });
|
|
257
|
+
return submittedTask(await safePost(dependencies.transport, {
|
|
258
|
+
path: "/gdesign/tool/v1/dify/call_async",
|
|
259
|
+
body: {
|
|
260
|
+
jsonrpc: "2.0",
|
|
261
|
+
id: 0,
|
|
262
|
+
method: "tools/call",
|
|
263
|
+
params: {
|
|
264
|
+
name: intent.name,
|
|
265
|
+
arguments: { ...intent.arguments, content_id: managedContentId }
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
credential: access.credential,
|
|
269
|
+
organizationId: access.organizationId,
|
|
270
|
+
signal
|
|
271
|
+
}));
|
|
272
|
+
});
|
|
273
|
+
dependencies.telemetry.annotate({ task_id: taskId });
|
|
274
|
+
return dependencies.telemetry.stage("wait", async () => {
|
|
275
|
+
let transientFailures = 0;
|
|
276
|
+
while (true) {
|
|
277
|
+
signal.throwIfAborted();
|
|
278
|
+
let response;
|
|
279
|
+
try {
|
|
280
|
+
response = await safePost(dependencies.transport, {
|
|
281
|
+
path: "/gdesign/tool/v1/dify/process/batch",
|
|
282
|
+
body: { task_ids: [taskId] },
|
|
283
|
+
credential: access.credential,
|
|
284
|
+
organizationId: access.organizationId,
|
|
285
|
+
signal
|
|
286
|
+
});
|
|
287
|
+
transientFailures = 0;
|
|
162
288
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (signal.aborted)
|
|
184
|
-
throw signal.reason;
|
|
185
|
-
if (!(error instanceof RemoteRequestError) || !error.transient)
|
|
186
|
-
throw error;
|
|
187
|
-
transientFailures += 1;
|
|
188
|
-
if (transientFailures > 3)
|
|
189
|
-
throw error;
|
|
190
|
-
await sleep(transientFailures * 1_000, signal);
|
|
191
|
-
continue;
|
|
289
|
+
catch (error) {
|
|
290
|
+
if (signal.aborted)
|
|
291
|
+
throw signal.reason;
|
|
292
|
+
if (!(error instanceof RemoteRequestError) || !error.transient)
|
|
293
|
+
throw error;
|
|
294
|
+
transientFailures += 1;
|
|
295
|
+
if (transientFailures > 3)
|
|
296
|
+
throw error;
|
|
297
|
+
await sleep(transientFailures * 1_000, signal);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const poll = pollResult(response, taskId);
|
|
301
|
+
if (poll.difyTaskId !== undefined) {
|
|
302
|
+
dependencies.telemetry.annotate({ dify_task_id: poll.difyTaskId });
|
|
303
|
+
}
|
|
304
|
+
if (poll.state === "failed")
|
|
305
|
+
throw poll.error;
|
|
306
|
+
if (poll.state === "complete")
|
|
307
|
+
return poll.content;
|
|
308
|
+
await sleep(2_000, signal);
|
|
192
309
|
}
|
|
193
|
-
|
|
194
|
-
if (result !== undefined)
|
|
195
|
-
return result;
|
|
196
|
-
await sleep(2_000, signal);
|
|
197
|
-
}
|
|
310
|
+
});
|
|
198
311
|
}
|
|
199
312
|
};
|
|
200
313
|
}
|
|
@@ -48,7 +48,7 @@ function remoteMedia(value, name) {
|
|
|
48
48
|
export function createToolUseCases(dependencies) {
|
|
49
49
|
async function load(access, signal) {
|
|
50
50
|
signal.throwIfAborted();
|
|
51
|
-
const catalog = await dependencies.catalog.load({ access, signal });
|
|
51
|
+
const catalog = await dependencies.telemetry.stage("catalog", () => (dependencies.catalog.load({ access, signal })));
|
|
52
52
|
signal.throwIfAborted();
|
|
53
53
|
for (const warning of catalog.warnings)
|
|
54
54
|
dependencies.warn(warning);
|
|
@@ -69,48 +69,77 @@ export function createToolUseCases(dependencies) {
|
|
|
69
69
|
},
|
|
70
70
|
async call({ input, access, signal }) {
|
|
71
71
|
const catalog = await load(access, signal);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
const model = await dependencies.telemetry.stage("input", () => {
|
|
73
|
+
const modelName = input.arguments.model;
|
|
74
|
+
if (typeof modelName !== "string")
|
|
75
|
+
throw new ToolInputError();
|
|
76
|
+
const selected = findToolModel(catalog, input.name, modelName);
|
|
77
|
+
assertModelArguments(selected, input.arguments);
|
|
78
|
+
return selected;
|
|
79
|
+
});
|
|
80
|
+
const { model: ignoredModel, ...parameters } = input.arguments;
|
|
81
|
+
void ignoredModel;
|
|
82
|
+
dependencies.telemetry.annotate({
|
|
83
|
+
tool_name: model.tool,
|
|
84
|
+
model_id: model.model,
|
|
85
|
+
parameters
|
|
86
|
+
});
|
|
77
87
|
const prompt = [];
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (parameter.
|
|
86
|
-
|
|
88
|
+
const requestParameters = {};
|
|
89
|
+
const prepare = async () => {
|
|
90
|
+
for (const parameter of model.parameters) {
|
|
91
|
+
signal.throwIfAborted();
|
|
92
|
+
const value = input.arguments[parameter.name];
|
|
93
|
+
if (value === undefined)
|
|
94
|
+
continue;
|
|
95
|
+
if (parameter.type === "string") {
|
|
96
|
+
if (parameter.name === "prompt") {
|
|
97
|
+
prompt.push({ type: "text", content: value });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
requestParameters[parameter.name] = value;
|
|
101
|
+
}
|
|
102
|
+
continue;
|
|
87
103
|
}
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
if (parameter.type === "number") {
|
|
105
|
+
requestParameters[parameter.name] = value;
|
|
106
|
+
continue;
|
|
90
107
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const values = parameter.type === "uri[]" ? value : [value];
|
|
94
|
-
for (const mediaUrl of values) {
|
|
95
|
-
signal.throwIfAborted();
|
|
96
|
-
if (mediaUrl.startsWith("file:")) {
|
|
97
|
-
const uploaded = await dependencies.uploader.upload({ url: mediaUrl }, access, signal);
|
|
108
|
+
const values = parameter.type === "uri[]" ? value : [value];
|
|
109
|
+
for (const mediaUrl of values) {
|
|
98
110
|
signal.throwIfAborted();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
if (mediaUrl.startsWith("file:")) {
|
|
112
|
+
const uploaded = await dependencies.uploader.upload({ url: mediaUrl }, access, signal);
|
|
113
|
+
signal.throwIfAborted();
|
|
114
|
+
prompt.push({
|
|
115
|
+
type: "media",
|
|
116
|
+
url: uploaded.url,
|
|
117
|
+
mime: uploaded.mediaType,
|
|
118
|
+
name: parameter.name
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
prompt.push(remoteMedia(mediaUrl, parameter.name));
|
|
123
|
+
}
|
|
108
124
|
}
|
|
109
125
|
}
|
|
126
|
+
};
|
|
127
|
+
const hasLocalMedia = model.parameters.some((parameter) => {
|
|
128
|
+
const value = input.arguments[parameter.name];
|
|
129
|
+
return parameter.type === "uri"
|
|
130
|
+
? typeof value === "string" && value.startsWith("file:")
|
|
131
|
+
: parameter.type === "uri[]"
|
|
132
|
+
&& Array.isArray(value) && value.some((url) => url.startsWith("file:"));
|
|
133
|
+
});
|
|
134
|
+
if (hasLocalMedia) {
|
|
135
|
+
await dependencies.telemetry.stage("upload", prepare);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
await prepare();
|
|
110
139
|
}
|
|
111
140
|
signal.throwIfAborted();
|
|
112
141
|
const content = await dependencies.execution.execute({
|
|
113
|
-
invocation: { model: model.model, prompt, parameters },
|
|
142
|
+
invocation: { model: model.model, prompt, parameters: requestParameters },
|
|
114
143
|
access,
|
|
115
144
|
signal
|
|
116
145
|
});
|
|
@@ -57,20 +57,22 @@ export function createUpdateService(options) {
|
|
|
57
57
|
return {
|
|
58
58
|
async run(signal) {
|
|
59
59
|
signal.throwIfAborted();
|
|
60
|
-
const latest = await fetchLatest(fetchPackage, signal);
|
|
60
|
+
const latest = await options.telemetry.stage("registry", () => (fetchLatest(fetchPackage, signal)));
|
|
61
61
|
signal.throwIfAborted();
|
|
62
62
|
const skillOptions = {
|
|
63
63
|
env,
|
|
64
64
|
...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
|
|
65
65
|
};
|
|
66
66
|
if (!gt(latest, options.currentVersion)) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
await options.telemetry.stage("sync", async () => {
|
|
68
|
+
try {
|
|
69
|
+
await syncSkills(options.bundledSkills, skillOptions);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
rethrowAbort(signal);
|
|
73
|
+
throw new UpdateError("UPDATE_FAILED", `gd-cli ${options.currentVersion} 无需更新,但 Agent Skill 同步失败。`, ["请解决冲突后重新执行 gd-cli update。"]);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
74
76
|
return { version: options.currentVersion, updated: false };
|
|
75
77
|
}
|
|
76
78
|
const binaryPath = options.binaryPath ?? process.argv[1] ?? "";
|
|
@@ -89,25 +91,29 @@ export function createUpdateService(options) {
|
|
|
89
91
|
const args = source.manager === "npm"
|
|
90
92
|
? ["install", "--global", "--allow-scripts=gaoding-cli", `gaoding-cli@${latest}`]
|
|
91
93
|
: ["add", "--global", "--allow-build=gaoding-cli", `gaoding-cli@${latest}`];
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
await options.telemetry.stage("install", async () => {
|
|
95
|
+
try {
|
|
96
|
+
await runProcess(command, args, signal);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
rethrowAbort(signal);
|
|
100
|
+
throw new UpdateError("UPDATE_FAILED", `gd-cli 更新到 ${latest} 失败。`, nextSteps);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
99
103
|
signal.throwIfAborted();
|
|
100
104
|
const targetSkills = options.bundledSkills.map((skill) => ({
|
|
101
105
|
...skill,
|
|
102
106
|
version: latest
|
|
103
107
|
}));
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
await options.telemetry.stage("verify", async () => {
|
|
109
|
+
try {
|
|
110
|
+
await verifySkills(targetSkills, skillOptions);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
rethrowAbort(signal);
|
|
114
|
+
throw new UpdateError("UPDATE_PARTIAL", `gd-cli 已更新到 ${latest},但 Agent Skill 验收失败。`, ["请重新执行 gd-cli update。"]);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
111
117
|
return { version: latest, updated: true };
|
|
112
118
|
}
|
|
113
119
|
};
|