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
package/dist/src/cli/errors.js
CHANGED
|
@@ -5,11 +5,14 @@ import { SsoRequestError } from "../features/auth/sso-service.js";
|
|
|
5
5
|
import { DeviceAuthorizationExpiredError } from "../features/auth/use-cases.js";
|
|
6
6
|
import { AgentInputError } from "../features/agent/use-cases.js";
|
|
7
7
|
import { ToolInputError } from "../features/tool/catalog.js";
|
|
8
|
+
import { ToolTaskFailedError } from "../features/tool/tool-api-adapter.js";
|
|
8
9
|
import { ObjectStorageUploadError } from "../features/dam/object-storage.js";
|
|
10
|
+
import { DamAssetNotFoundError } from "../features/dam/dam-api-adapter.js";
|
|
9
11
|
import { DamInputError } from "../features/dam/use-cases.js";
|
|
10
12
|
import { OrganizationResponseError } from "../features/org/org-service.js";
|
|
11
13
|
import { OrganizationBindFailedError, OrganizationInvalidError, OrgUsageError } from "../features/org/use-cases.js";
|
|
12
14
|
import { RemoteRequestError } from "../platform/signed-http-transport.js";
|
|
15
|
+
import { RemoteProtocolError } from "../platform/remote-protocol.js";
|
|
13
16
|
import { InputContractError, OutputContractError } from "../bootstrap/validators.js";
|
|
14
17
|
import { JsonInputError } from "../platform/json-input.js";
|
|
15
18
|
import { LocalFileInputError } from "../platform/safe-upload-file.js";
|
|
@@ -59,13 +62,22 @@ export function mapCliError(error, options) {
|
|
|
59
62
|
|| error instanceof CommanderError) {
|
|
60
63
|
return failure("USAGE_ERROR", "命令或参数无效,请查看 --help。", 2);
|
|
61
64
|
}
|
|
65
|
+
if (error instanceof RemoteProtocolError) {
|
|
66
|
+
return failure("REMOTE_PROTOCOL_INCOMPATIBLE", "稿定服务返回了当前 CLI 无法安全处理的结果;为避免重复创作,已停止处理。", 1);
|
|
67
|
+
}
|
|
68
|
+
if (error instanceof ToolTaskFailedError) {
|
|
69
|
+
return failure("TOOL_TASK_FAILED", "稿定工具任务执行失败。", 1);
|
|
70
|
+
}
|
|
71
|
+
if (error instanceof DamAssetNotFoundError) {
|
|
72
|
+
return failure("DAM_ASSET_NOT_FOUND", "未找到指定的 DAM 素材。", 1);
|
|
73
|
+
}
|
|
62
74
|
if (error instanceof RemoteRequestError
|
|
63
75
|
|| error instanceof SsoRequestError
|
|
64
76
|
|| error instanceof DeviceAuthorizationExpiredError
|
|
65
77
|
|| error instanceof OrganizationResponseError
|
|
66
78
|
|| error instanceof OrganizationBindFailedError
|
|
67
79
|
|| error instanceof ObjectStorageUploadError) {
|
|
68
|
-
return failure("REMOTE_REQUEST_FAILED", "
|
|
80
|
+
return failure("REMOTE_REQUEST_FAILED", "稿定服务请求失败。", 1);
|
|
69
81
|
}
|
|
70
82
|
if (error instanceof OutputContractError) {
|
|
71
83
|
return failure("INTERNAL_ERROR", "CLI 内部结果校验失败。", 1);
|
|
@@ -77,6 +89,27 @@ export function mapCliError(error, options) {
|
|
|
77
89
|
}
|
|
78
90
|
return failure("INTERNAL_ERROR", "CLI 发生内部错误。", 1);
|
|
79
91
|
}
|
|
92
|
+
export function classifyTelemetryError(error) {
|
|
93
|
+
const outcome = mapCliError(error, { aborted: false });
|
|
94
|
+
const remoteError = error instanceof RemoteRequestError
|
|
95
|
+
|| error instanceof RemoteProtocolError
|
|
96
|
+
|| error instanceof ToolTaskFailedError
|
|
97
|
+
? error
|
|
98
|
+
: undefined;
|
|
99
|
+
return {
|
|
100
|
+
outcome: outcome.kind === "interrupted" ? "interrupted" : "failure",
|
|
101
|
+
...(outcome.kind === "failure" ? { errorCode: outcome.failure.code } : {}),
|
|
102
|
+
...(error instanceof RemoteRequestError && error.status !== undefined
|
|
103
|
+
? { httpStatus: error.status }
|
|
104
|
+
: {}),
|
|
105
|
+
...(remoteError?.remoteCode === undefined
|
|
106
|
+
? {}
|
|
107
|
+
: { remoteErrorCode: remoteError.remoteCode }),
|
|
108
|
+
...(remoteError?.remoteBody === undefined
|
|
109
|
+
? {}
|
|
110
|
+
: { remoteErrorBody: remoteError.remoteBody })
|
|
111
|
+
};
|
|
112
|
+
}
|
|
80
113
|
function failure(code, message, exitCode, nextSteps) {
|
|
81
114
|
return {
|
|
82
115
|
kind: "failure",
|
|
@@ -11,7 +11,9 @@ export function registerModelCommands(program, runtime) {
|
|
|
11
11
|
bindAction(list, "organization", async (context, signal) => {
|
|
12
12
|
const selectedTool = list.opts().tool;
|
|
13
13
|
const input = selectedTool === undefined ? {} : { tool: selectedTool };
|
|
14
|
-
runtime.
|
|
14
|
+
await runtime.telemetry.stage("input", async () => {
|
|
15
|
+
runtime.validators.modelListInput(input);
|
|
16
|
+
});
|
|
15
17
|
const result = await runtime.tool.listModels({
|
|
16
18
|
input,
|
|
17
19
|
access: {
|
|
@@ -20,9 +22,13 @@ export function registerModelCommands(program, runtime) {
|
|
|
20
22
|
},
|
|
21
23
|
signal
|
|
22
24
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
if (selectedTool !== undefined)
|
|
26
|
+
runtime.telemetry.annotate({ tool_name: selectedTool });
|
|
27
|
+
await runtime.telemetry.stage("output", async () => {
|
|
28
|
+
runtime.validators.modelListOutput(result);
|
|
29
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
30
|
+
});
|
|
31
|
+
}, { operation: "model.list" });
|
|
26
32
|
const get = model.command("get")
|
|
27
33
|
.description("查看模型完整信息")
|
|
28
34
|
.argument("<model>", "模型机器标识")
|
|
@@ -32,16 +38,24 @@ export function registerModelCommands(program, runtime) {
|
|
|
32
38
|
if (typeof modelName !== "string" || modelName.trim() === "")
|
|
33
39
|
throw new CliUsageError();
|
|
34
40
|
const input = { model: modelName };
|
|
35
|
-
runtime.
|
|
41
|
+
await runtime.telemetry.stage("input", async () => {
|
|
42
|
+
runtime.validators.modelGetInput(input);
|
|
43
|
+
});
|
|
44
|
+
const access = {
|
|
45
|
+
credential: context.state.credential,
|
|
46
|
+
organizationId: context.state.organization.id
|
|
47
|
+
};
|
|
36
48
|
const result = await runtime.tool.getModel({
|
|
37
49
|
input,
|
|
38
|
-
access
|
|
39
|
-
credential: context.state.credential,
|
|
40
|
-
organizationId: context.state.organization.id
|
|
41
|
-
},
|
|
50
|
+
access,
|
|
42
51
|
signal
|
|
43
52
|
});
|
|
44
|
-
runtime.
|
|
45
|
-
runtime.
|
|
53
|
+
runtime.telemetry.annotate({ model_id: modelName });
|
|
54
|
+
await runtime.telemetry.stage("output", async () => {
|
|
55
|
+
runtime.validators.modelGetOutput(result);
|
|
56
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
57
|
+
});
|
|
58
|
+
}, {
|
|
59
|
+
operation: "model.get"
|
|
46
60
|
});
|
|
47
61
|
}
|
|
@@ -10,23 +10,27 @@ export function registerOrgCommands(program, runtime) {
|
|
|
10
10
|
.option("--json", "输出 JSON");
|
|
11
11
|
bindAction(list, "credential", async (context, signal) => {
|
|
12
12
|
const result = await runtime.org.list({ state: context.state, signal });
|
|
13
|
-
runtime.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
await runtime.telemetry.stage("output", async () => {
|
|
14
|
+
runtime.validators.orgList(result);
|
|
15
|
+
runtime.presenter.result(result, {
|
|
16
|
+
json: list.opts().json === true,
|
|
17
|
+
view: orgListView
|
|
18
|
+
});
|
|
17
19
|
});
|
|
18
|
-
});
|
|
20
|
+
}, { operation: "org.list" });
|
|
19
21
|
const current = leaf(org.command("current"))
|
|
20
22
|
.description("查看当前组织")
|
|
21
23
|
.option("--json", "输出 JSON");
|
|
22
24
|
bindAction(current, "none", async () => {
|
|
23
25
|
const result = await runtime.org.current();
|
|
24
|
-
runtime.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
await runtime.telemetry.stage("output", async () => {
|
|
27
|
+
runtime.validators.orgCurrent(result);
|
|
28
|
+
runtime.presenter.result(result, {
|
|
29
|
+
json: current.opts().json === true,
|
|
30
|
+
view: orgCurrentView
|
|
31
|
+
});
|
|
28
32
|
});
|
|
29
|
-
});
|
|
33
|
+
}, { operation: "org.current" });
|
|
30
34
|
const switchCommand = leaf(org.command("switch"))
|
|
31
35
|
.description("切换当前组织")
|
|
32
36
|
.option("--org <org-id>", "指定组织 ID");
|
|
@@ -41,8 +45,10 @@ export function registerOrgCommands(program, runtime) {
|
|
|
41
45
|
: { organizationId }),
|
|
42
46
|
signal
|
|
43
47
|
});
|
|
44
|
-
runtime.
|
|
45
|
-
|
|
48
|
+
await runtime.telemetry.stage("output", async () => {
|
|
49
|
+
runtime.presenter.success(`已切换到${record.publicName} (${record.id})。`);
|
|
50
|
+
});
|
|
51
|
+
}, { operation: "org.switch" });
|
|
46
52
|
}
|
|
47
53
|
function leaf(command) {
|
|
48
54
|
return command.allowExcessArguments(false);
|
|
@@ -27,7 +27,14 @@ export function createPresenter(options) {
|
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
if (presentation.json) {
|
|
30
|
-
options.writeError(`${JSON.stringify({
|
|
30
|
+
options.writeError(`${JSON.stringify({
|
|
31
|
+
error: {
|
|
32
|
+
...outcome.failure,
|
|
33
|
+
...(presentation.traceId
|
|
34
|
+
? { trace_id: presentation.traceId }
|
|
35
|
+
: {})
|
|
36
|
+
}
|
|
37
|
+
})}\n`);
|
|
31
38
|
return;
|
|
32
39
|
}
|
|
33
40
|
options.writeError(`${outcome.failure.code}: ${outcome.failure.message}\n`);
|
|
@@ -35,6 +42,9 @@ export function createPresenter(options) {
|
|
|
35
42
|
if (nextSteps.length > 0) {
|
|
36
43
|
options.writeError(`下一步: ${nextSteps.join(",")}\n`);
|
|
37
44
|
}
|
|
45
|
+
if (presentation.traceId) {
|
|
46
|
+
options.writeError(`诊断 ID: ${presentation.traceId}\n`);
|
|
47
|
+
}
|
|
38
48
|
}
|
|
39
49
|
};
|
|
40
50
|
}
|
|
@@ -15,13 +15,15 @@ export function registerToolCommands(program, runtime) {
|
|
|
15
15
|
},
|
|
16
16
|
signal
|
|
17
17
|
});
|
|
18
|
-
runtime.
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
await runtime.telemetry.stage("output", async () => {
|
|
19
|
+
runtime.validators.toolListOutput(result);
|
|
20
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
21
|
+
});
|
|
22
|
+
}, { operation: "tool.list" });
|
|
21
23
|
const call = tool.command("call")
|
|
22
24
|
.description("调用创作工具")
|
|
23
25
|
.argument("<tool>", "工具机器标识")
|
|
24
|
-
.option("--schema", "
|
|
26
|
+
.option("--schema", "输出当前工具所有模型参数并集的输入 Schema")
|
|
25
27
|
.option("--input <file|->", "从文件或标准输入读取参数 JSON")
|
|
26
28
|
.allowExcessArguments(false);
|
|
27
29
|
bindPreparedAction(call, "organization", async (signal) => {
|
|
@@ -51,7 +53,10 @@ export function registerToolCommands(program, runtime) {
|
|
|
51
53
|
access,
|
|
52
54
|
signal
|
|
53
55
|
});
|
|
54
|
-
runtime.
|
|
56
|
+
runtime.telemetry.annotate({ tool_name: prepared.name });
|
|
57
|
+
await runtime.telemetry.stage("output", async () => {
|
|
58
|
+
runtime.io.writeOut(`${JSON.stringify(schema)}\n`);
|
|
59
|
+
});
|
|
55
60
|
return;
|
|
56
61
|
}
|
|
57
62
|
const result = await runtime.tool.call({
|
|
@@ -59,7 +64,14 @@ export function registerToolCommands(program, runtime) {
|
|
|
59
64
|
access,
|
|
60
65
|
signal
|
|
61
66
|
});
|
|
62
|
-
runtime.
|
|
63
|
-
|
|
67
|
+
await runtime.telemetry.stage("output", async () => {
|
|
68
|
+
runtime.validators.toolCallOutput(result);
|
|
69
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
70
|
+
});
|
|
71
|
+
}, {
|
|
72
|
+
operation: "tool.call",
|
|
73
|
+
mode: () => call.opts().schema === true
|
|
74
|
+
? "schema"
|
|
75
|
+
: "execute"
|
|
64
76
|
});
|
|
65
77
|
}
|
|
@@ -5,8 +5,10 @@ export function registerUpdateCommand(program, runtime) {
|
|
|
5
5
|
.allowExcessArguments(false);
|
|
6
6
|
bindAction(update, "none", async (_context, signal) => {
|
|
7
7
|
const result = await runtime.update.run(signal);
|
|
8
|
-
runtime.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
await runtime.telemetry.stage("output", async () => {
|
|
9
|
+
runtime.presenter.success(result.updated
|
|
10
|
+
? `gd-cli 已更新到 ${result.version},Agent Skill 已同步。`
|
|
11
|
+
: `gd-cli ${result.version} 已是最新版本,Agent Skill 已同步。`);
|
|
12
|
+
});
|
|
13
|
+
}, { operation: "update" });
|
|
12
14
|
}
|
|
@@ -10,22 +10,27 @@ export function createCreativeAgentAdapter(dependencies) {
|
|
|
10
10
|
localMessageId: dependencies.idFactory()
|
|
11
11
|
}
|
|
12
12
|
: { localMessageId: dependencies.idFactory() };
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
const streamed = await dependencies.telemetry.stage("execute", async () => {
|
|
14
|
+
const stream = await dependencies.transport.postStream({
|
|
15
|
+
path: "/ai-agent/v1/thread/completion",
|
|
16
|
+
body: buildCreativeRequest(message, ids),
|
|
17
|
+
accept: "text/event-stream",
|
|
18
|
+
credential: access.credential,
|
|
19
|
+
organizationId: access.organizationId,
|
|
20
|
+
signal
|
|
21
|
+
});
|
|
22
|
+
return parseCreativeStream(stream, signal);
|
|
20
23
|
});
|
|
21
|
-
const contextId = creativeContextId(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const contextId = creativeContextId(streamed);
|
|
25
|
+
return dependencies.telemetry.stage("result", async () => {
|
|
26
|
+
const messages = await dependencies.transport.getJson({
|
|
27
|
+
path: `/ai-agent/v1/thread/${encodeURIComponent(contextId)}/messages`,
|
|
28
|
+
credential: access.credential,
|
|
29
|
+
organizationId: access.organizationId,
|
|
30
|
+
signal
|
|
31
|
+
});
|
|
32
|
+
return normalizeCreativeMessages(creativeTurnMessages(messages, ids.localMessageId));
|
|
27
33
|
});
|
|
28
|
-
return normalizeCreativeMessages(creativeTurnMessages(messages, ids.localMessageId));
|
|
29
34
|
}
|
|
30
35
|
};
|
|
31
36
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RemoteProtocolError } from "../../platform/remote-protocol.js";
|
|
2
2
|
export function buildCreativeRequest(message, ids) {
|
|
3
3
|
const prompt = [];
|
|
4
4
|
const textParts = [];
|
|
@@ -110,7 +110,7 @@ function nonEmptyString(value) {
|
|
|
110
110
|
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
111
111
|
}
|
|
112
112
|
function fail() {
|
|
113
|
-
throw new
|
|
113
|
+
throw new RemoteProtocolError();
|
|
114
114
|
}
|
|
115
115
|
export function creativeContextId(messages) {
|
|
116
116
|
if (messages.some((message) => message.event === "system_error"))
|
|
@@ -125,7 +125,11 @@ export function creativeTurnMessages(value, localMessageId) {
|
|
|
125
125
|
return fail();
|
|
126
126
|
}
|
|
127
127
|
const messages = value;
|
|
128
|
-
const start = messages.findIndex((message) =>
|
|
128
|
+
const start = messages.findIndex((message) => {
|
|
129
|
+
if (message.local_message_id !== localMessageId)
|
|
130
|
+
return false;
|
|
131
|
+
return message.role === "user" || contentOf(message)?.type === "function_response";
|
|
132
|
+
});
|
|
129
133
|
if (start < 0)
|
|
130
134
|
return fail();
|
|
131
135
|
return messages.slice(start);
|
|
@@ -37,69 +37,78 @@ export function createAgentUseCases(dependencies) {
|
|
|
37
37
|
async send({ input, access, signal }) {
|
|
38
38
|
signal.throwIfAborted();
|
|
39
39
|
const prepared = [];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
if ("url" in part) {
|
|
47
|
-
const role = part.metadata?.role ?? "reference";
|
|
48
|
-
if (part.url.startsWith("file:")) {
|
|
49
|
-
const uploadInput = {
|
|
50
|
-
url: part.url,
|
|
51
|
-
...(part.mediaType === undefined ? {} : { mediaType: part.mediaType }),
|
|
52
|
-
...(part.filename === undefined ? {} : { filename: part.filename })
|
|
53
|
-
};
|
|
54
|
-
const asset = await dependencies.uploader.upload(uploadInput, access, signal);
|
|
55
|
-
prepared.push({ kind: "asset", asset, role });
|
|
40
|
+
const prepare = async () => {
|
|
41
|
+
for (const part of input.message.parts) {
|
|
42
|
+
signal.throwIfAborted();
|
|
43
|
+
if ("text" in part) {
|
|
44
|
+
prepared.push({ kind: "text", text: part.text });
|
|
56
45
|
continue;
|
|
57
46
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
if ("url" in part) {
|
|
48
|
+
const role = part.metadata?.role ?? "reference";
|
|
49
|
+
if (part.url.startsWith("file:")) {
|
|
50
|
+
const uploadInput = {
|
|
51
|
+
url: part.url,
|
|
52
|
+
...(part.mediaType === undefined ? {} : { mediaType: part.mediaType }),
|
|
53
|
+
...(part.filename === undefined ? {} : { filename: part.filename })
|
|
54
|
+
};
|
|
55
|
+
const asset = await dependencies.uploader.upload(uploadInput, access, signal);
|
|
56
|
+
prepared.push({ kind: "asset", asset, role });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
let url;
|
|
60
|
+
try {
|
|
61
|
+
url = parseSafeRemoteAssetUrl(part.url);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof UrlSafetyError)
|
|
65
|
+
throw new AgentInputError();
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
const filename = part.filename ?? pathnameFilename(url);
|
|
69
|
+
prepared.push({
|
|
70
|
+
kind: "asset",
|
|
71
|
+
asset: {
|
|
72
|
+
url: part.url,
|
|
73
|
+
mediaType: part.mediaType ?? inferMediaType(filename),
|
|
74
|
+
filename,
|
|
75
|
+
fromUserUpload: false
|
|
76
|
+
},
|
|
77
|
+
role
|
|
78
|
+
});
|
|
79
|
+
continue;
|
|
61
80
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
81
|
+
if ("questionMessageId" in part.data) {
|
|
82
|
+
prepared.push({
|
|
83
|
+
kind: "answers",
|
|
84
|
+
data: {
|
|
85
|
+
questionMessageId: part.data.questionMessageId,
|
|
86
|
+
answers: part.data.answers.map((answer) => ({
|
|
87
|
+
question: answer.question,
|
|
88
|
+
values: [...answer.values]
|
|
89
|
+
}))
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
continue;
|
|
66
93
|
}
|
|
67
|
-
const filename = part.filename ?? pathnameFilename(url);
|
|
68
94
|
prepared.push({
|
|
69
|
-
kind: "
|
|
70
|
-
asset: {
|
|
71
|
-
url: part.url,
|
|
72
|
-
mediaType: part.mediaType ?? inferMediaType(filename),
|
|
73
|
-
filename,
|
|
74
|
-
fromUserUpload: false
|
|
75
|
-
},
|
|
76
|
-
role
|
|
77
|
-
});
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if ("questionMessageId" in part.data) {
|
|
81
|
-
prepared.push({
|
|
82
|
-
kind: "answers",
|
|
95
|
+
kind: "parameters",
|
|
83
96
|
data: {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
...(part.data.ratio === undefined ? {} : { ratio: part.data.ratio }),
|
|
98
|
+
...(part.data.resolution === undefined ? {} : { resolution: part.data.resolution }),
|
|
99
|
+
...(part.data.durationSeconds === undefined
|
|
100
|
+
? {}
|
|
101
|
+
: { durationSeconds: part.data.durationSeconds })
|
|
89
102
|
}
|
|
90
103
|
});
|
|
91
|
-
continue;
|
|
92
104
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
: { durationSeconds: part.data.durationSeconds })
|
|
101
|
-
}
|
|
102
|
-
});
|
|
105
|
+
};
|
|
106
|
+
if (input.message.parts.some((part) => (typeof part === "object" && part !== null
|
|
107
|
+
&& "url" in part && typeof part.url === "string" && part.url.startsWith("file:")))) {
|
|
108
|
+
await dependencies.telemetry.stage("upload", prepare);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
await prepare();
|
|
103
112
|
}
|
|
104
113
|
signal.throwIfAborted();
|
|
105
114
|
return dependencies.completion.complete({
|