u1s1-cli 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -116,6 +116,14 @@ export interface ImageGenRequest {
116
116
  /** 1K/2K/4K 或 宽x高(如 2048x2048);缺省由服务端定(2K)。 */
117
117
  size?: string;
118
118
  }
119
+ /**
120
+ * 新网关把结果同时放进响应头。这样即使 Cloudflare 到 Node 的 JSON body
121
+ * 在生成完成后被 Undici 报 `terminated`,也能继续下载已经计费的那张图。
122
+ */
123
+ export declare function readGeneratedImageResponse(resp: Response): Promise<{
124
+ url: string;
125
+ size: string | null;
126
+ }>;
119
127
  /** 生图走网关代理(方舟 key 只在服务端);返回 TOS 图片 URL(24h 有效),调用方应立即下载。 */
120
128
  export declare function generateImage(cfg: Pick<CliConfig, "baseUrl" | "apiKey">, req: ImageGenRequest, signal?: AbortSignal): Promise<{
121
129
  url: string;
package/dist/api.js CHANGED
@@ -109,6 +109,52 @@ export async function renderPage(cfg, url, signal) {
109
109
  }
110
110
  return (await resp.json());
111
111
  }
112
+ const IMAGE_URL_HEADER = "x-u1s1-image-url";
113
+ const IMAGE_SIZE_HEADER = "x-u1s1-image-size";
114
+ function imageResultFromHeaders(resp) {
115
+ const encodedUrl = resp.headers.get(IMAGE_URL_HEADER);
116
+ if (!encodedUrl)
117
+ return null;
118
+ try {
119
+ const url = decodeURIComponent(encodedUrl);
120
+ const parsed = new URL(url);
121
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
122
+ return null;
123
+ const encodedSize = resp.headers.get(IMAGE_SIZE_HEADER);
124
+ return { url, size: encodedSize ? decodeURIComponent(encodedSize) : null };
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ }
130
+ function responseErrorDetail(error) {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ const cause = error instanceof Error ? error.cause : undefined;
133
+ const code = cause && typeof cause === "object" && "code" in cause && typeof cause.code === "string" ? cause.code : "";
134
+ return code && !message.includes(code) ? `${message} (${code})` : message;
135
+ }
136
+ /**
137
+ * 新网关把结果同时放进响应头。这样即使 Cloudflare 到 Node 的 JSON body
138
+ * 在生成完成后被 Undici 报 `terminated`,也能继续下载已经计费的那张图。
139
+ */
140
+ export async function readGeneratedImageResponse(resp) {
141
+ const headerResult = imageResultFromHeaders(resp);
142
+ if (headerResult) {
143
+ await resp.body?.cancel().catch(() => undefined);
144
+ return headerResult;
145
+ }
146
+ try {
147
+ const body = (await resp.json());
148
+ if (typeof body.url !== "string" || !/^https?:\/\//.test(body.url)) {
149
+ throw new Error("服务端没有返回图片下载地址");
150
+ }
151
+ return { url: body.url, size: typeof body.size === "string" ? body.size : null };
152
+ }
153
+ catch (error) {
154
+ throw new Error(`图片可能已经生成,但客户端下载结果响应失败: ${responseErrorDetail(error)}。` +
155
+ "不要重新调用 generate_image,请升级 u1s1 后再试", { cause: error });
156
+ }
157
+ }
112
158
  /** 生图走网关代理(方舟 key 只在服务端);返回 TOS 图片 URL(24h 有效),调用方应立即下载。 */
113
159
  export async function generateImage(cfg, req, signal) {
114
160
  if (!cfg.apiKey)
@@ -136,7 +182,7 @@ export async function generateImage(cfg, req, signal) {
136
182
  const body = (await resp.json().catch(() => null));
137
183
  throw new Error(body?.error?.message ?? `图片生成服务返回 ${resp.status},稍后再试`);
138
184
  }
139
- return (await resp.json());
185
+ return readGeneratedImageResponse(resp);
140
186
  }
141
187
  export async function fetchMe(cfg) {
142
188
  if (!cfg.apiKey)
package/dist/tools.js CHANGED
@@ -352,6 +352,7 @@ export function createImageTool(cfg) {
352
352
  promptGuidelines: [
353
353
  "Use generate_image when the user wants a picture created or an existing image modified (logo, illustration, poster, placeholder art, style change).",
354
354
  "Each call generates one image and costs the user credits; refine the prompt first instead of regenerating repeatedly.",
355
+ "If an error says the image may/already has been generated or says not to call generate_image again, stop immediately; never retry with a new generation.",
355
356
  "To edit an existing image, pass its path in `images` and describe only the change in `prompt`.",
356
357
  ],
357
358
  parameters: Type.Object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {