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

# 실행

> 앱에서 Flow 호출, 트레이스·피드백·신호를 상관 id로 엮기

앱이 실제로 **Flow를 부르는** 자리입니다. 인증은 그 Flow의 **트리거 시크릿**만으로 됩니다. 여기선 PAT이 필요 없습니다.

## `flows.run`

```ts theme={null}
const r = await nora.flows.run("support", "보장 범위를 알려줘", {
  variables: { plan: "pro" },   // {{plan}} 오버라이드
  model: "gpt-4o",              // 선택: 에이전트 모델 오버라이드
  idempotencyKey: "req_123",    // 선택
});

r.traceId;   // 언제나 있음, 실패해도
r.status;    // "ok" | "partial" | "needs_review" | "failed" | string (서버 신설 상태 대비 확장 가능)
r.outputs;   // partial 이어도 여기까지는 있음
r.notices;   // 실행을 제약했지만 실패는 아닌 것 (예: 툴 호출 한도 도달)
r.failure;   // status === "failed" 일 때만: { code, message, retryable, at }
```

옵션:

* `variables` 호출 단위로 Flow 변수를 오버라이드. 트리거의 `variables` 필드와 같은 모양.
* `model`이 실행에서만 에이전트 모델을 오버라이드 (워크스페이스 라우팅 · BYOK 존중).
* `idempotencyKey` 같은 키로 두 번 보내면 서버가 첫 실행을 그대로 돌려줍니다.

**실행 결과 실패는 예외를 던지지 않습니다.** SDK가 `traceId`와 부분 출력을 돌려 주니 로그·재시도·다운그레이드에 쓰세요. 반환값의 `.status`와 `.failure`를 반드시 봅니다. 전송·인증·요청 오류는 예외로 던집니다. [에러](/ko/sdk/errors) 참고.

## `newTraceRef`

서버 응답으로 `traceId`가 오기 전에 미리 상관 id를 만들어 둡니다.

```ts theme={null}
const ref = nora.newTraceRef();
myLogger.info({ ref, event: "flow.about-to-run" });

const r = await nora.flows.run("support", input, { /* ... */ });
myLogger.info({ ref, traceId: r.traceId, status: r.status });
```

실행 전에 미리 앱 로그(또는 Slack 메시지)에 참조를 남기고 싶을 때 씁니다.

## 흔한 패턴

### partial이면 다운그레이드

```ts theme={null}
const r = await nora.flows.run("support", input);

if (r.status === "failed") {
  return { text: fallbackAnswer, traceId: r.traceId, failure: r.failure };
}
if (r.status === "needs_review") {
  await queueForReview(r.traceId);
  return { text: r.outputs.answer, review: true };
}
return { text: r.outputs.answer };
```

### Idempotent 재시도

HTTP 레이어에서 재시도 중이라면(핸들러가 타임아웃했지만 서버가 이미 처리 중일 수 있는 경우), 재시도 때 같은 `idempotencyKey`를 넘기세요. 서버가 원래 실행의 `traceId`를 그대로 돌려주고 새로 돌리지 않습니다.

```ts theme={null}
const key = `req_${requestId}`;
try {
  return await nora.flows.run("support", input, { idempotencyKey: key });
} catch (e) {
  if (isTransient(e)) return await nora.flows.run("support", input, { idempotencyKey: key });
  throw e;
}
```

### notice를 실패가 아닌 안내로

`notices[]`는 실행을 제약했지만 실패는 아닌 것들입니다(툴 호출 한도 도달, 리트리벌 결과 0, 출력 잘림). 로그 · 관리자 UI에 노출하되 최종 사용자에게 에러로 띄우지 마세요.

## MCP · CLI로 같은 일

SDK [게시 전](/ko/sdk/overview)이라 MCP · CLI로 같은 작업이 됩니다.

```bash theme={null}
# MCP 툴: PAT / 세션으로 인증, 트리거 시크릿 불필요
run_flow { slug, input, variables?, model?, threadId?, userId?, test? }

# CLI
nora flows run <slug> --input "보장 범위를 알려줘" \
  [--variables '{"plan":"pro"}'] [--model gpt-4o] [--test]
```

둘 다 `flows.run`과 같은 봉투(`traceId` · `status` · `outputs` · `notices` · `failure`)를 돌려줍니다.
