테마
게시한 제품의 PTI 변경
이미 승인 기반 등록으로 게시한 자사 PartType Information(PTI)의 제조사 품명, 부품 분류, 계획 생산 사업장을 변경합니다. 가격·재고·이미지·설명, 품번·제조사 BPN·Catena-X ID, 정책·BOM·PCF는 이 변경안에 포함할 수 없습니다. 외부·다운로드·이전 방식으로 등록한 제품 등 지원하지 않는 제품은 오류를 반환합니다.
프로그램과 이번 연결에 products:read, products:write가 필요합니다. products:write는 조직 소유자만 동의할 수 있습니다. 기존 연결의 data:updates, products:register, products:read가 제품 변경 권한으로 확장되지는 않습니다. 프로그램의 요청 허용 목록에 없다면 프로그램 재등록과 연결 교체를 먼저 진행합니다.
mermaid
flowchart TD
A[제품 목록과 현재 PTI 조회] --> B[기대 버전과 변경 필드로 변경안 준비]
B --> C[소유자가 웹에서 변경 전후와 발행 순서 확인]
C --> D{동일한 내용 승인}
D -->|승인| E[AI에 돌아와 다음 단계 키 조회]
E --> F[선택한 키 하나만 명시적으로 실행]
F --> G{결과 확인}
G -->|다음 단계 있음| E
G -->|발행 완료| H[현재 PTI 조회로 새 버전 확인]
G -->|결과 불확실| I[중단하고 운영자에게 확인 요청]
D -->|철회 또는 만료| J[새 발행 중단]1. 안정적인 제품 ID와 현재 PTI 버전 찾기
SDK 첫 조회의 연결된 client를 사용합니다. list_products에서 제품을 찾고 get_product에서 본문 조회용 Asset ID를 확인합니다. 다음 값은 합성 예시이며 실제 서버 응답으로 교체하세요.
js
async function call(name, arguments_) {
const response = await client.callTool({ name, arguments: arguments_ });
if (response.isError) throw new Error(JSON.stringify(response.structuredContent));
return response.structuredContent?.result
?? JSON.parse(response.content.find(p => p.type === "text").text).result;
}
const products = await call("infirium_list_products", { skip: 0, take: 20 });
console.log(products.items); // id = 안정적인 Product ID
const productId = "11111111-2222-4333-8444-555555555555";
const detail = await call("infirium_get_product", { id: productId });
console.log(detail.assets.items); // PTI assetId 확인
const pti = await call("infirium_get_product_data", {
id: "22222222-2222-4333-8444-555555555555"
});
console.log(pti.assetId, pti.ptiRevision, pti.submodel.data);ptiRevision은 최초 PTI에서 1, 첫 변경 발행 후 2인 양의 정수입니다. expectedRevision에는 이 값을 사용합니다. 기존 revision 필드는 호환성을 위해 남아 있으며 최초 등록에서는 시간값일 수 있습니다. 해석하거나 숫자로 변환하지 마세요. 목록에서는 현재 표시되는 검증된 PTI 이름이나 품번으로 검색할 수 있습니다. 변경 전 이름과 과거 버전의 이름은 현재 이름 검색에 포함되지 않습니다.
2. 변경안 준비
createKey는 이번 변경 요청에 한 번 생성하고 보관합니다. 같은 키와 같은 입력은 같은 검토를 반환하며 다른 입력으로 재사용하면 충돌합니다. expectedRevision이 현재 PTI와 다르면 현재 데이터를 다시 조회해 새로운 검토를 준비하세요.
js
const input = {
createKey: crypto.randomUUID(),
productId,
expectedRevision: pti.ptiRevision,
changes: {
partTypeInformation: {
nameAtManufacturer: "High-efficiency electric motor EM-240"
}
}
};
const prepared = await call("infirium_prepare_product_update", input);
console.log(prepared.reviewId, prepared.reviewUrl);
console.log(prepared.manifest.current, prepared.manifest.proposed);허용 배열은 전체 교체합니다. partClassification: []는 빈 목록으로 바꾸고, partClassification: null은 선택 필드를 제거합니다. partSitesInformationAsPlanned도 같습니다. 생략한 필드는 유지됩니다. 변경 본문은 최대 256 KiB이며 전체 요청의 1 MiB 제한도 적용됩니다. 추가 키나 무변경 요청은 거절합니다.
3. 소유자가 변경 전후 승인
서버가 반환한 reviewUrl을 원래 조직 소유자에게 표시하세요. 주소는 설정된 웹 origin과 언어를 사용한 /[lang]/program/product-update-review?reviewId=…입니다. 소유자 검토 화면은 검토 ID가 포함된 반환 링크로 여세요. 일반 소유자 세션에서만 승인할 수 있으며 대리·읽기 전용 세션은 사용할 수 없습니다. AI에게 로그인 토큰을 넘기거나 승인 호출을 맡기지 마세요.

모바일 검토 화면

화면에서 제품과 PTI 버전 전환, 각 필드의 변경 전후, 유지되는 계약 제공과 발행 순서를 확인하고 확인란을 선택한 뒤 제품 변경을 승인합니다. 승인 요청은 화면의 decisionDigest와 wireDigest 모두에 묶입니다. 원본·권한·정책 등이 바뀌면 새 변경안을 준비해야 합니다. 해시와 전체 검토 JSON은 기술 상세를 펼쳐 확인할 수 있습니다.
4. 승인 후 한 단계씩 명시적으로 실행
원래 클라이언트·grant로 돌아와 승인 상태를 조회합니다. 준비만 된 검토에는 실행 키가 없습니다. approved이고 nextStepKey가 있는지 확인한 후 선택한 단계만 실행합니다. 다음 예제의 각 호출은 사람이 승인한 같은 검토를 대상으로 합니다.
js
const reviewId = prepared.reviewId;
let review = await call("infirium_get_product_update", { reviewId });
if (review.status !== "approved" || !review.nextStepKey) {
throw new Error("Owner approval is required");
}
// 1: 새 PTI asset
const assetStepKey = review.nextStepKey;
review = await call("infirium_execute_product_update", { reviewId, stepKey: assetStepKey });
// 응답과 다음 단계가 확인된 뒤 2: 첫 번째 원래 계약 제공
review = await call("infirium_execute_product_update", { reviewId, stepKey: review.nextStepKey });
// 단일 계약 제공 제품의 3: DTR submodel descriptor 추가
review = await call("infirium_execute_product_update", { reviewId, stepKey: review.nextStepKey });
console.log(review.status, review.steps);원래 계약 제공이 두 개라면 3번째 단계는 두 번째 계약 제공이고 4번째가 DTR descriptor입니다. 준비 응답의 manifest.steps와 manifest.offers로 확인하세요. 두 제공은 원래 Saturn/Jupiter 버전과 정책 연결을 각각 유지합니다.
js
// 두 계약 제공 제품에서만: 3번째 계약 단계의 확정 응답을 확인한 뒤 4번째 descriptor 실행
review = await call("infirium_execute_product_update", { reviewId, stepKey: review.nextStepKey });completed가 현재 버전 전환 완료입니다. 아직 명시적 로컬 발행이 필요한 accepted 응답과 nextStepKey가 있다면 그 반환 키로 한 번 더 명시적으로 실행합니다. 이미 완료한 assetStepKey를 다시 보내도 다음 단계로 진행하지 않습니다. needs_reconciliation이나 전송 결과 불확실 상태이면 중단하세요. 새 키, 새 변경안, 연속 반복 호출로 재전송을 유도하지 않습니다.
발행 후 안정적인 원래 PTI assetId로 다시 get_product_data를 호출하면 현재 head의 assetId, 본문과 ptiRevision을 받습니다. 과거 PTI 버전 assetId를 명시하면 해당 버전의 정확한 본문과 historical 표시를 받습니다. 최초 등록·과거 asset·agreement가 제공하던 bytes는 유지되므로 기존 계약이 자동으로 최신 PTI로 바뀌지는 않습니다. 기존 BOM·PCF 승인 자료의 원본 PTI가 변경됐다면 새 검토가 필요합니다.
취소와 A2A
infirium_cancel_product_update({ reviewId })는 후속 제공자 전송과 로컬 발행을 막습니다. 이미 전송한 외부 작업의 결과·기록을 지우지는 않습니다. 소유자 화면의 승인 철회도 후속 실행을 막습니다. A2A CancelTask는 로컬 작업 전달의 취소이며 제품 변경안을 취소하는 도구를 대신하지 않습니다.
A2A에서도 같은 네 도구와 입력을 구조화된 data part로 사용합니다. 준비·승인 대기·다음 단계가 있는 결과는 TASK_STATE_INPUT_REQUIRED이며 소유자 웹 승인은 별도입니다.
json
{
"message": {
"messageId": "product-update-get-001",
"role": "ROLE_USER",
"parts": [{ "data": {
"toolName": "infirium_get_product_update",
"arguments": { "reviewId": "33333333-2222-4333-8444-555555555555" }
}}]
}
}
