콘텐츠로 이동

세션 서비스 5분 안에 실행하기

@tansr/serve는 tansr의 Agent 세션 엔진입니다. npm 패키지 하나로 당신의 Node 서비스에 내장되어, 밖으로는 다중 세션 REST + SSE 프로토콜 면(통합 호출 표면 /api(0.13.0부터 GA)와 그 뒤의 /v2 세션 프로토콜)을 노출하고, 안으로는 당신의 앱 키로 tansr 플랫폼에 연결해 실제로 모델을 호출합니다. 이것은 게이트웨이가 아닙니다. 사용자가 어떻게 로그인하고, 어떻게 속도를 제한하고, 어떻게 과금하는지는 모두 당신의 체계에 속합니다. 엔진은 전송, 프로토콜, 세션 거버넌스만 담당합니다. 이 페이지는 @tansr/serve 0.15.1(2026-10-10 공개, 현재 npm latest)을 기준으로 확인했습니다.

Android 0.5.0, iOS 0.4.0, HarmonyOS HAR 0.2.0부터의 공개 모바일 SDK는 /api만 쓰고, 그보다 앞선 공개 패키지는 여전히 /v2를 씁니다. Node 쪽 얇은 클라이언트는 @tansr/api-client 0.4.0(하위 진입점 ./api. 2026-10-06 공개이며, 이 버전부터 동결된 하위 진입점 ./sdk2 / ./terminal도 routePrefixes를 넘기지 않으면 기본으로 /api를 호출합니다)입니다. 새 통합은 바로 /api로 가세요. 같은 세션, 같은 페이로드 바이트에 tansr-* 응답 헤더 넷과 통합 오류 봉투가 더해집니다. /v2는 0.13.0부터 내부 어댑터 진입점으로 정의되며 1.0.0에서 외부 진입점이 제거됩니다. 0.15.0부터 구 접두사 /v2, /v3/*의 응답에는 Deprecation / Link 퇴역 헤더가 붙지만, 구 접두사 창은 0.15.1 기준으로도 기본값이 readwrite(읽기와 쓰기 모두 종전처럼 처리)이므로 이미 운영 중인 /v2 호출을 지금 바꿀 필요는 없습니다. 창 손잡이와 일정은 배포와 인증을 보세요.

플랫폼 또는 호스트에서 앱 역할 설정

섹션 제목: “플랫폼 또는 호스트에서 앱 역할 설정”

모바일의 시스템 프롬프트는 플랫폼 앱 설정 또는 serve 호스트에서 설정하며, /v2의 prompt에 넣지 않습니다. platform.system을 생략하면 플랫폼 기본값을 사용합니다. 코드로 관리하는 업무 세그먼트는 platform.system에, 호스트 보충 설명은 platform.systemAppend에 둡니다. 기본값 fallback은 명시적인 업무 세그먼트([] 포함)가 플랫폼 세그먼트를 대체하도록 허용합니다. prepend는 SDK 세그먼트가 []여도 플랫폼 세그먼트를 앞에 유지합니다.

이 옵션들은 @tansr/serve 0.8.0부터 제공되며, 플랫폼 측은 2026-09-14에 프로덕션에 공개되었습니다. 이들은 텍스트 조합만 제어하며 권한을 대체하지 않습니다. 플랫폼 프롬프트와 정책은 다음 새 턴 전에 새로 고쳐지고, 현재 실행 중인 턴은 기존 설정을 유지합니다. 기존 세션, attach, 기록은 계속 사용할 수 있으며, 역할을 바꾸기 위해 세션을 다시 열 필요가 없습니다. 애플리케이션 시스템 프롬프트와 SDK 결합 정책의 serve 전체 예시를 참고하세요.

  • Node.js ≥ 22.19.
  • 콘솔에서 모바일 앱(Android / iOS / HarmonyOS용) 또는 서버 앱을 만들어 appid와 appkey를 얻습니다.
  • 당신의 로그인 상태 체계: 엔진은 요청 하나를 endUserId 하나로 매핑해 주기만을 요구하며, 나머지는 관여하지 않습니다.
터미널 창
npm install @tansr/serve # 现行 0.15.1

유일한 서드파티 런타임 의존성은 zod입니다. tansr 내부 패키지는 컴파일 시 인라인되어 당신의 의존성 트리에 나타나지 않습니다. 0.13.0부터 패키지에는 하위 진입점 @tansr/serve/extensions(SDK2 아카이브 / 캐시 / 터미널 서비스 호스트, 명시적 조립 필요)와 @tansr/serve/process도 들어 있지만, 이 페이지의 루트 진입점 사용법은 거기에 의존하지 않습니다.

자격 증명: appid / appkey는 서버 쪽에

섹션 제목: “자격 증명: appid / appkey는 서버 쪽에”

세션 서비스의 인증은 세 층으로 나뉩니다. 소속을 기억하면 잘못 두지 않습니다.

층 자격 증명 소속
클라이언트 ↔ 세션 서비스(/api, /v2) 당신이 정한 로그인 상태 token(JWT, session cookie, OAuth 모두 가능) 완전히 당신의 것. 엔진은 authenticate 훅을 통해 endUserId만 받음
세션 서비스 ↔ tansr 플랫폼 appid + appkey 서비스 프로세스가 보유. 엔진은 이것으로 각 최종 사용자를 위한 app_user 토큰을 발급
클라이언트가 보유한 appid 공개 앱 식별자 내려줄 수 있음. 자격 증명이 아님

레드라인 세 가지: appkey는 절대 단말에 내려주지 않습니다. app_user 토큰은 절대 세션 서비스 밖으로 나가지 않습니다. 세션 id는 인증 요소가 아닙니다(각 엔드포인트가 독립적으로 소속을 검증합니다).

appid / appkey는 환경 변수에 넣습니다(이름은 자유. 예시는 공식 예제의 TANSR_APP_KEY_ID / TANSR_APP_KEY를 따름). 코드나 저장소에 쓰지 마세요.

실행되는 최소 뼈대. 인증 훅, 내장 실제 어셈블리, 세션 디스크 저장, 시작:

import {
createAgentSessionFactory,
createServeAgentSessionStore,
registerBuiltinLocales,
startServer,
} from '@tansr/serve';
registerBuiltinLocales(); // 可选:错误体文案本地化
// 真装配:appid/appkey → 每个终端用户一枚短期令牌 → 内核查询环真调模型
const build = createAgentSessionFactory({
platform: {
apiBaseUrl: 'https://api.tansr.com',
appId: process.env.TANSR_APP_KEY_ID!,
appKey: process.env.TANSR_APP_KEY!, // 恒不下发端、恒不入日志
},
store: createServeAgentSessionStore({ dir: '/var/lib/my-agent/sessions' }), // 生产恒接
cwd: process.cwd(),
});
const server = await startServer({
host: '127.0.0.1',
port: 8787,
token: process.env.MY_V1_TOKEN!, // /v1 面的 Bearer;fail-closed 必填;v2 在场时 /v1 缺省关闭,与 /api、/v2 鉴权互不相通
createSession: build.factory,
version: '1.0.0',
v2: { // v2 在场 = 同时装配 /api 门面与 /v2 内部入口
// 唯一鉴权面:你的登录态 → endUserId;返回 null 即 401
authenticate: async (req) => {
const user = await myAuth.verify(req.headers['authorization']);
return user ? { endUserId: user.id } : null;
},
createSession: build.factory,
store: build.storeReader, // 让休眠会话可列表 / 可 resume
},
});

store는 반드시 연결하세요. 연결하지 않으면 프로세스가 재시작되는 순간 모든 활성 세션의 컨텍스트가 완전히 사라지고, 클라이언트의 resume은 항상 409 resume_unavailable이 됩니다.

프로세스 시그널은 호스트의 책임입니다. 엔진은 당신을 대신해 SIGTERM을 감시하지 않습니다. 최소한 server.drain({ timeoutMs: 30_000 })을 연결한 뒤 종료하세요. 자세한 내용은 배포와 인증을 참고하세요.

먼저 준비된 예제로 프로토콜을 보고 싶나요? 저장소 안의 예제 examples/serve-demo에서 pnpm start(pnpm real과 동일)는 실제 모델 진입점 agent-real.ts를 실행하며, examples/serve-demo/.env에서 TANSR_APP_KEY_ID / TANSR_APP_KEY(선택적으로 TANSR_API_BASE)를 읽습니다. 자격 증명이 없으면 에코로 돌아가지 않고 종료합니다. 상주 스위치를 설정하지 않으면 스모크 한 턴만 자동으로 돌리고 종료합니다. curl이나 모바일 연동용 상주 서버를 띄우려면 .env에 DEMO_SERVE_ONLY=1을 추가하고 포트는 DEMO_PORT로 지정하세요(소스 기본값 8799, 예제 README는 8788 사용). 에코 Agent는 2026-09-14부터 저장소 내부 테스트 픽스처일 뿐이며 공개된 오프라인 시작 명령은 없습니다.

curl로 직접 한 바퀴 돌아 봅니다. <당신의 로그인 token>은 당신의 체계가 발급하고 authenticate가 검증할 수 있는 토큰입니다. 아래는 통합 호출 표면 /api를 사용합니다. /api/sessions를 /v2/sessions로 바꿔도 같은 세션, 같은 응답 본문을 얻습니다(tansr-* 응답 헤더 넷이 빠지고 오류 본문은 예전 봉투가 됩니다).

먼저 이 서비스에 무엇이 조립되어 있는지 확인합니다(manifest revision 7. @tansr/serve 0.14.0부터이며 0.15.1에서도 변동 없음):

터미널 창
curl -s http://127.0.0.1:8787/api/manifest -H "Authorization: Bearer <你的登录 token>" -D - -o /dev/null
# tansr-contract: unified-v1 / tansr-manifest-revision: 7 / tansr-domain: discovery / tansr-schema-hash: …

세션 만들기(첫 prompt 포함):

터미널 창
curl -s -X POST http://127.0.0.1:8787/api/sessions \
-H "Authorization: Bearer <你的登录 token>" \
-H "Content-Type: application/json" \
-d '{"prompt":"你好,介绍一下你能做什么"}'
{ "sessionId": "…", "resumed": false, "lastSeq": 0 }

후속 입력:

터미널 창
curl -s -X POST http://127.0.0.1:8787/api/sessions/<sessionId>/messages \
-H "Authorization: Bearer <你的登录 token>" \
-H "Content-Type: application/json" \
-d '{"prompt":"再简短一点"}'

202 { "sessionId", "accepted": true }가 반환됩니다. 실패하면 /api는 통합 봉투 { "contract": "unified-v1", "code", "status", "retryAction", "detail": { "domainCode", … } }를 반환합니다. switch (code) 하나로 모든 도메인을 다룰 수 있고, 원래 /v2 코드가 필요하면 detail.domainCode를 읽습니다.

SSE 이벤트 스트림을 구독합니다.

터미널 창
curl -N http://127.0.0.1:8787/api/sessions/<sessionId>/events \
-H "Authorization: Bearer <你的登录 token>"

첫 프레임은 retry: 3000이고, 그 뒤로는 커널 이벤트 하나에 프레임 하나입니다: id: <seq>와 data: <KernelEvent JSON>이며 event: 이름은 붙지 않습니다. 제어 프레임(도구 요청, 권한 요청, 질문)에만 event: server.* 이름이 붙습니다. 15초마다 : hb 주석 하트비트가 한 건 옵니다. 프레임 바이트는 /v2와 동일합니다. 요청 헤더 tansr-event-envelope: unified-v1을 추가로 보낼 때만 data:가 7키 통합 이벤트 봉투로 바뀝니다(원래 이벤트는 raw에 들어 있습니다).

연결이 끊긴 뒤 마지막으로 소비한 seq를 붙여 다시 연결하면, 서버는 링 버퍼에서 끊긴 지점 이후의 이벤트를 재전송합니다.

터미널 창
curl -N http://127.0.0.1:8787/api/sessions/<sessionId>/events \
-H "Authorization: Bearer <你的登录 token>" \
-H "Last-Event-ID: 42"

lastSeq는 복구 앵커이며, 단말은 항상 값 그대로 이어서 구독합니다. 새 세션은 0을 반환하고, 휴면 세션(live: false)에 대한 GET /v2/sessions/:id는 저장소에 기록된 실제 수위를 반환하며, resume 뒤의 새 기원(epoch)은 그 수위 + 1부터 이어집니다(이 두 가지는 @tansr/serve 0.9.0부터의 동작입니다. 0.8.x는 두 곳 모두 0을 반환합니다). 휴면 판정은 live로 하고, lastSeq === 0으로 판정하지 마세요. 너무 오래된 Last-Event-ID로 재연결하면 server.replay.gap 프레임(reason: 'evicted')을 받습니다. 이때는 투영을 버리고 /history에서 다시 구축합니다. 3단계 복구 체인은 v2 프로토콜과 webhook을 참고하세요.

tansr serve --token <값>으로도 상주 서비스를 띄울 수 있지만, 이것은 단일 운영자용 /v1 면(POST /v1/sessions, GET /v1/sessions/:id/events 등 여섯 엔드포인트, 같은 Bearer token 하나)으로, 오케스트레이션 시스템 연동에 적합하며 다중 테넌트 제품 백엔드가 아닙니다. tansr serve --v2는 /v2 면도 CLI 형태에 올리는 것으로(tansr CLI 0.6.0부터 사용할 수 있습니다), 0.10.0부터는 /api 파사드도 함께 조립하며 --v2가 있으면 /v1 면은 기본적으로 꺼집니다. 꼭 남겨야 할 때 쓰는 --legacy-v1 / TANSR_SERVE_LEGACY_V1=1은 0.10.1부터 사용 중단 예정입니다(server.deprecated_option 경고를 내고 1.0.0에서 제거). CLI 형태의 현재 버전은 0.10.3(npm @tansr/cli, 2026-10-10. @tansr/serve 0.15.1과 같은 서비스 구현을 인라인하며, 0.10.2 / 0.10.3에서 추가된 명령이나 플래그는 없습니다)입니다. SDK2 아카이브 / 캐시 / 터미널 서비스 호스트는 CLI 형태에서 --host-module <absolute.cjs> --host-module-sha256 <sha256>을 통해서만 쓸 수 있습니다. 위의 @tansr/serve npm 내장 형태(0.8.0 이상, 현재 0.15.1)도 계속 사용할 수 있습니다.

  • 배포와 인증: 인증 훅, /v1 기본 비활성화와 구 접두사 일정, 정상 종료, 관측 엔드포인트, 다중 레플리카 샤딩.
  • v2 프로토콜과 webhook: 엔드포인트 전체 형태, 3단계 복구 체인, 턴 종료 아웃바운드 알림과 서명.
  • 보존 기간과 거버넌스: 보존 창, 유휴 회수, 동시 실행 상한, 세션 저장소, 0.14.0의 요청 헤더 셋.
  • 환경 변수 표: 모든 TANSR_SERVE_* 손잡이.
  • SDK 2.0 확장 진입점: @tansr/serve/extensions 명시적 호스트, @tansr/api-client 0.4.0, 성능 공개.