> ## Documentation Index
> Fetch the complete documentation index at: https://docs.youka.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Tác nhân AI

> Quy tắc vận hành và mẫu quy trình làm việc cho tác nhân gọi Youka CLI hoặc API

Youka được thiết kế để được điều khiển bởi các tác nhân. Mọi lệnh CLI đều trả về một phong bì JSON có thể đọc bằng máy, mọi thao tác ghi đều hỗ trợ khóa idempotency, và API công khai cung cấp cùng bề mặt với cùng ngữ nghĩa. Trang này tổng hợp các quy tắc vận hành mà tác giả tác nhân cần biết trước khi kết nối Youka vào một quy trình làm việc.

## Bắt đầu

Nếu bạn đang thiết lập một tác nhân lần đầu, hãy cài Youka CLI trước, sau đó cài kỹ năng Youka karaoke:

```bash theme={null}
npm install -g @youka/cli
npx skills add https://github.com/youka-io/skills --skill youka-karaoke
```

Việc này cung cấp cho tác nhân một kỹ năng Youka có sẵn được hậu thuẫn bởi CLI. Khi đã cài xong, hãy dùng các mẫu quy trình bên dưới để tạo video karaoke, tùy biến phong cách, và xuất tệp MP4 một cách an toàn.

### Nhắc lệnh cho tác nhân

Sau khi cài CLI và skill, bạn có thể giao cho tác nhân một nhiệm vụ trực tiếp như sau:

<CodeGroup>
  ```text local-file theme={null}
  Use Youka to create a karaoke video from /path/to/song.mp3. Transcribe the lyrics in English, use a clean karaoke subtitle style, export the final video in 1080p, and save it as ./karaoke.mp4.
  ```

  ```text url theme={null}
  Use Youka to create a karaoke video from https://example.com/song.mp4. If URL dependencies are missing, install them first. Then transcribe the lyrics automatically, use a clean karaoke subtitle style, export the final video, and save it as ./karaoke.mp4.
  ```
</CodeGroup>

## Quy tắc vận hành

<CardGroup cols={2}>
  <Card title="Luôn dùng --json" icon="code">
    Trên CLI, luôn truyền `--json`. Trên API, luôn đặt `Accept:
            application/json`. Không bao giờ phân tích đầu ra dành cho con người.
  </Card>

  <Card title="Luôn gửi một khóa idempotency" icon="rotate">
    Mọi thao tác ghi nên mang một khóa idempotency ổn định để việc thử lại sau khi
    timeout trả về kết quả ban đầu thay vì nhân đôi công việc.
  </Card>

  <Card title="Đọc lại trạng thái bền vững" icon="database">
    Đừng tin phản hồi đột biến đã cũ. Sau một tác vụ kết thúc, hãy đọc lại
    project hoặc export để lấy trạng thái cuối cùng.
  </Card>

  <Card title="Poll với backoff" icon="hourglass">
    Bắt đầu với khoảng 2–3 giây. Tăng giãn cách theo cấp số nhân cho các job dài.
    Tôn trọng phản hồi 429.
  </Card>
</CardGroup>

## Hợp đồng đầu ra

Mọi lệnh CLI ở chế độ `--json` ghi chính xác một phong bì ra stdout.

Thành công:

```json theme={null}
{
  "schemaVersion": "1",
  "ok": true,
  "data": { "id": "prj_abc123", "title": "My Song" }
}
```

Thất bại:

```json theme={null}
{
  "schemaVersion": "1",
  "ok": false,
  "error": {
    "code": "CONFLICT",
    "message": "A request with this Idempotency-Key is already in progress.",
    "retryable": true
  }
}
```

Mã thoát:

| Code | Meaning                                                  | Retry?                      |
| ---- | -------------------------------------------------------- | --------------------------- |
| `0`  | Thành công.                                              | N/A                         |
| `1`  | Lỗi thời gian chạy (network, API, rendering).            | Kiểm tra `error.retryable`. |
| `2`  | Đầu vào không hợp lệ (flag sai, payload không đọc được). | Không — sửa đầu vào.        |

## Quy trình end-to-end

Quy trình chuẩn cho tác nhân là: tạo project, đợi, export, tải xuống kết quả. Đây là mẫu đầy đủ với cả triển khai CLI và SDK.

<CodeGroup>
  ```bash CLI theme={null}
  # 1. Create the project and wait for stems + lyrics sync to finish
  PROJECT_JSON=$(youka project create ./song.mp3 \
    --mode transcribe \
    --lang en \
    --wait \
    --idempotency-key "create-song-2026-04-08-001" \
    --json)

  PROJECT_ID=$(echo "$PROJECT_JSON" | jq -r '.data.projectId')

  # 2. Start and wait for an export
  EXPORT_JSON=$(youka export create "$PROJECT_ID" \
    --resolution 1080p \
    --quality high \
    --wait \
    --download \
    --output ./karaoke.mp4 \
    --idempotency-key "export-$PROJECT_ID-v1" \
    --json)

  echo "Done:" "$(echo "$EXPORT_JSON" | jq -r '.data.fileUrl')"
  ```

  ```ts SDK theme={null}
  import { YoukaClient, YoukaRequestError, YoukaTaskError } from "@youka/vi/sdk";

  const client = new YoukaClient({ apiKey: process.env.YOUKA_API_KEY! });

  async function createAndExport() {
    // 1. Create the project and wait for stems + lyrics sync
    const created = await client.projects.create(
      {
        source: { type: "path", path: "./song.mp3" },
        lyricsSource: { type: "transcribe", language: "en" },
      },
      { idempotencyKey: "create-song-2026-04-08-001" },
    );

    const { project } = await client.projects.wait(created);

    // 2. Start and wait for an export
    const exportResult = await client.exports.create(
      project.id,
      { resolution: "1080p", quality: "high" },
      { idempotencyKey: `export-${project.id}-v1` },
    );

    const finalized = await client.exports.wait(exportResult);

    // 3. Download the file
    await client.exports.download(finalized, {
      output: "./karaoke.mp4",
    });
  }

  createAndExport().catch((error) => {
    if (error instanceof YoukaRequestError && error.retryable) {
      // Retry with the same idempotency keys
    }
    if (error instanceof YoukaTaskError) {
      console.error("Task failed:", error.code, error.task.error);
    }
    throw error;
  });
  ```
</CodeGroup>

## Hướng dẫn polling

Hầu hết các thao tác ghi trả về operation handles trong SDK. Ưu tiên `client.projects.wait(...)` và `client.exports.wait(...)`, và chỉ hạ xuống `client.tasks.*` khi bạn thực sự cần truy cập task mức thấp.

| Job type                             | Recommended initial interval | Max wait |
| ------------------------------------ | ---------------------------- | -------- |
| Tạo project (stems + đồng bộ lyrics) | 3 s                          | 15 min   |
| Chỉ tách stem                        | 3 s                          | 10 min   |
| Chỉ đồng bộ lyrics                   | 2 s                          | 5 min    |
| Render export                        | 3 s                          | 30 min   |

Trên CLI, `--wait` sẽ xử lý polling cho bạn. Trên SDK, các helper wait dùng khoảng 2 s theo mặc định và chấp nhận `pollIntervalMs`.

<Tip>
  Tôn trọng phản hồi 429. Khi bị rate limit, hãy back off ít nhất theo header `Retry-After`
  (hoặc 30 s nếu không có).
</Tip>

## Khóa idempotency

Mọi thao tác create và update đều hỗ trợ một khóa idempotency. Quy tắc:

* Dùng một khóa **ổn định, duy nhất, mang tính quyết định** cho mỗi đột biến logic. Tốt: `create-song-${sourceHash}`. Không tốt: một UUID mới cho mỗi lần retry.
* Tái sử dụng **cùng** khóa qua các lần retry. Server nhận ra việc phát lại và trả về kết quả ban đầu.
* Khóa có phạm vi theo từng tài khoản và hết hạn sau 24 giờ.
* Nếu server trả về `IDEMPOTENT_REPLAY_IN_PROGRESS` (HTTP 202), request ban đầu vẫn đang chạy. Hãy đợi và retry với cùng khóa.

Mẫu ví dụ:

```ts theme={null}
const key = `create-${sha256(sourceBytes)}`;

try {
  return await client.projects.create(body, { idempotencyKey: key });
} catch (error) {
  if (error instanceof YoukaRequestError && error.retryable) {
    // Safe to retry with the same key
    return await client.projects.create(body, { idempotencyKey: key });
  }
  throw error;
}
```

Xem [API idempotency](/vi/api/idempotency) để biết hợp đồng đầy đủ.

## Khôi phục lỗi

Rẽ nhánh theo `error.code` và `error.retryable`. Các trường hợp phổ biến:

| Code                                  | Cause                                                      | Action                                                  |
| ------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------- |
| `INVALID_REQUEST`                     | Request body không vượt qua xác thực schema.               | Sửa payload. Không retry.                               |
| `UNAUTHORIZED`                        | Thiếu hoặc API key không hợp lệ.                           | Hiển thị cho người gọi. Không retry.                    |
| `NOT_FOUND`                           | Tài nguyên không tồn tại hoặc bạn không có quyền truy cập. | Không retry.                                            |
| `CONFLICT` (409)                      | Xung đột phiên bản hoặc va chạm idempotency.               | Retry với cùng khóa idempotency.                        |
| `TOO_MANY_REQUESTS` (429)             | Rate limit.                                                | Back off theo `Retry-After` hoặc 30 s.                  |
| `INTERNAL_SERVER_ERROR` (500)         | Lỗi máy chủ tạm thời.                                      | Retry tối đa 3 lần với backoff.                         |
| `IDEMPOTENT_REPLAY_IN_PROGRESS` (202) | Request trước vẫn đang chạy.                               | Đợi và retry với cùng khóa.                             |
| `TASK_FAILED`                         | Task async kết thúc thất bại.                              | Hiển thị `error.task.error` cho người gọi. Không retry. |
| `TASK_TIMED_OUT`                      | Task async vượt quá ngân sách thời gian.                   | Có thể retry an toàn một lần.                           |

## Khám phá các trường có thể thay đổi

Trước khi mutate preset, hãy fetch schema của preset để mô hình biết các field hợp lệ và kiểu giá trị:

<CodeGroup>
  ```bash CLI theme={null}
  # Preset body schema
  youka preset schema --json
  ```

  ```ts SDK theme={null}
  import { KaraokePresetSchema } from "@youka/vi/sdk";

  const presetSchema = KaraokePresetSchema.toJSONSchema();
  ```
</CodeGroup>

Đối với project settings, ưu tiên đọc project settings hiện tại trước, sau đó gửi một body cập nhật tối thiểu qua `youka project settings <id> --body ...`.

Fetch một lần cho mỗi phiên tác nhân và cache kết quả.

## Tác nhân song song

Khi nhiều tác nhân chạy đồng thời trên cùng một tài khoản:

* Giới hạn phạm vi khóa idempotency theo **cả** danh tính tác nhân và đột biến logic: `agent-${agentId}-create-${sourceHash}`. Điều này ngăn retry của một tác nhân va chạm với request mới của tác nhân khác.
* Giữ các thao tác đọc không bị ràng buộc — các request `GET` rẻ và không có tác dụng phụ.
* Dùng một hàng đợi duy nhất cho `POST /projects/{projectId}/exports` theo từng project nếu bạn cần lịch sử export theo thứ tự. Nếu không, các export có thể đến không theo thứ tự.

## Tiếp theo

* [CLI global options](/vi/cli/global-options) — mọi flag có sẵn cho tác nhân
* [SDK errors](/vi/sdk/errors) — tham chiếu đầy đủ các lớp lỗi
* [API async jobs](/vi/api/async-jobs) — hợp đồng polling
* [API idempotency](/vi/api/idempotency) — hợp đồng idempotency
