AI Code Import — I/O 定義
このページは apps/code-import/(src/code_import/ 配下の Python パッケージ code_import)に実装する code-import ワーカーの 公式 I/O 契約 です。フィールド・形状・ステータス値・失敗区分の変更はすべて契約変更であり、コードをマージする前に本ページおよび test-cases.ja.md に反映してください。
読み順: 概要 → 入力 → 処理契約 → 出力 → エラーハンドリング → 冪等性。文末の フィールド参照 はルックアップ用です。
概要
flowchart LR
api[guinness-backend] -->|INSERT code status=0| RDB[(PostgreSQL)]
api -->|SendMessage| Q[(SQS code-import)]
Q --> L[AI Code Import worker]
L -->|validate optional reference| S3[(S3 preview metadata)]
L -->|one semantic run| LLM[(DESC_MODEL)]
L -->|one batch, two inputs| EMB[(Embeddings 512)]
L -->|transactional replace + invalidate| Doc[(DocumentDB code + code_index)]
L -->|POST /v1/webhooks/ai-status| api
api -->|UPDATE code status=1 or 2| RDB
| 項目 | 値 |
|---|---|
| トリガー | code-import キュー上の SQS レコード |
| 入力 | SQS メッセージ + 任意 canonical S3 preview reference |
| 出力 | DocumentDB アップサート 1 件(code コレクション)+ Webhook POST 1 件 |
| DocumentDB 書き込み | evidence 変更時に scoped code replace と code_index.status=stale を同一 transaction で実行 |
| RDB 書き込み | なし — ワーカーは PostgreSQL / MySQL にアクセスしない |
| 外部呼び出し | deterministic source parsing、PydanticAI semantic agent 1 回、provider-selected embeddings(1 call / 2 inputs)、Webhook POST |
| AI フレームワーク | changed record ごとに PydanticAI Agent 1 回。embedding は configured OpenAI-compatible client |
入力
1. SQS メッセージ(トリガー)
Lambda は標準の AWS SQS イベントを受信します。バックエンド(apps/app/src/services/code.ts)が code-import キューに投入し、各ジョブの Records[*].body に JSON 文字列が入ります。
{
"Records": [{
"messageId": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
"body": "{\"code_id\":\"660e8400-e29b-41d4-a716-446655440001\",\"organization_id\":1,\"project_id\":42,\"name\":\"button-primary\",\"type\":1,\"based_on\":0,\"source_code\":\"<button className='btn btn-primary'>Click me</button>\",\"css_code\":\".btn-primary { background:#007bff; }\",\"img_url\":\"s3://bucket/code/42_button.png\"}",
"attributes": { "ApproximateReceiveCount": "1" },
"eventSource": "aws:sqs"
}]
}
ボディフィールド(Records[*].body をパース後、Pydantic の CodeImportMessage で検証 — 概要 §1)。
| フィールド | 型 | 必須 | 備考 |
|---|---|---|---|
code_id |
string (UUID) | ✓ | RFC 4122 UUID v4 — DocumentDB の _id および Webhook の recordId になる |
organization_id |
integer | ✓ | テナント分離;DocDB に永続 |
project_id |
integer | ✓ | 下流のベクトル検索スコープ用 |
name |
string | ✓ | そのまま保存 |
type |
integer | ✓ | 0 = page、1 = code |
based_on |
integer | ✓ | 0 imported、1 design、2 wireframe |
source_code |
string | ✓ | 非空;上流は ≤200 KB を推奨 — 未解決事項 |
css_code |
string | null | ✗ | あればそのまま保存 |
img_url |
string | null | ✗ | 任意 canonical preview reference。metadata として保存し、worker は download しない |
component_level |
string | null | ✗ | 任意 hint: atom, molecule, organism, template, component |
Body のアンラップ。 Lambda/API Gateway の差を吸収するため、ハンドラは次を(優先度順で)許容します。
- フラット — 上記のオブジェクト自体が
body - SQS-in-SQS — 外側の
Records[0].bodyに内側の JSON 文字列 - API Gateway プロキシ —
body.body(任意でisBase64Encoded) - 二重ラップ(レガシー) — テストフィクスチャ にある余分な
Recordsネスト;フラットなCodeImportMessageが見えるまでアンラップ
それ以外の形状は検証エラー。
2. S3: オプションのコンポーネントスクリーンショット
| プロパティ | 値 |
|---|---|
| ソース | img_url が非 null のとき |
| 検証 | bucket は S3_BUCKET_NAME、key は org/project/code の canonical preview key、extension は png/jpg/webp |
| Worker access | S3 GET なし。visual.metadata.image_url に reference のみ保存 |
| 無い場合 | image URL は null。semantic/context import は同じ |
3. RDB 行の状態(読み取りは他システム)
ワーカーは PostgreSQL の code 行を直接読まない。バックエンドが SQS 公開前に行を作成(通常 status = 0)。完了は Webhook で通知し、ステートマシンのオーナーはバックエンド。
処理契約
SQS レコードごとに同期的に以下の順で処理する:
- 必要なら アンラップ したうえで
CodeImportMessageをパース+検証。 - preview reference 検証 —
img_urlがある場合 canonical bucket/key を要求し、download しない。 - code context 抽出 — name/source/CSS/component-level hint から family、variant、structured imports、exports、references、class names、tokens、context text を deterministic に生成する。
- コード解析エージェント(テキスト) — 入力:
source_code+ 任意css_code、出力:semantic_words(5〜10 文字列)。 - 埋め込み — configured provider を 1 回、入力 2 つ(deterministic semantic identity、context text)、512 dimensions で呼ぶ。
data[0]→ semantic、data[1]→ context。 - ドキュメント組み立て — 出力 1 のロック形状。
- DocumentDB write — scoped
replace_one(..., upsert=True)と scoped singletoncode_index.status=staleを同一 transaction で実行。 result.keywordsにsemantic_wordsを載せた成功 Webhook を POST(embeddingDimsは常に512)。
一致する processing.hash がある場合は既存 vector/keyword を再利用し、必要なら preview URL のみ patch して success を送る。部分書き込みは禁止。
出力
出力 1: DocumentDB code コレクション(アップサート)
仕様 §5.2 に一致 — 要約:
{
"_id": "660e8400-e29b-41d4-a716-446655440001",
"organization_id": 1,
"project_id": 42,
"name": "button-primary",
"type": 1,
"based_on": 0,
"source_code": "<button className='btn btn-primary'>Click me</button>",
"css_code": ".btn-primary { background:#007bff; }",
"visual": {
"metadata": {
"name": "button-primary",
"image_url": "s3://bucket/1/42/code/660e8400-e29b-41d4-a716-446655440001.png"
}
},
"semantics": {
"metadata": { "words": ["submit", "checkout", "transaction", "action", "primary"] },
"vector_embedding": [/* 512 floats */]
},
"context": {
"metadata": {
"component_level": "atom",
"family": "button",
"variant": "primary",
"imports": [{"source": "react", "specifiers": [], "default_import": "React", "namespace_import": null}],
"exports": ["Button"],
"referenced_components": ["button"],
"class_names": ["btn-primary"],
"source_tokens": ["button", "primary", "click"],
"text": "level=atom family=button variant=primary exports=Button references=button tokens=button primary click"
},
"vector_embedding": [/* 512 floats */]
},
"processing": {
"hash": "<64-character SHA-256 fingerprint>"
}
}
| フィールド | ルール |
|---|---|
visual.metadata.image_url |
img_url のコピー;スクショなしの場合は null |
semantics.metadata.words |
Code Semantics エージェントの semantic_words と同一 |
semantics.vector_embedding |
ちょうど 512 次元 — deterministic semantic identity text の埋め込み |
context.metadata |
level、family、variant、structured imports、exports、references、class names、tokens、canonical text |
context.vector_embedding |
ちょうど 512 次元 — context.metadata.text の埋め込み |
processing.hash |
unchanged import を再利用する stable SHA-256 fingerprint |
ベクトルインデックス(packages/models/documentdb/code.py が冪等に作成):
| インデックス名 | パス | 次元 | 類似度 | HNSW m |
efConstruction |
|---|---|---|---|---|---|
codeSemanticVectorIndex |
semantics.vector_embedding |
512 | cosine | 16 | 64 |
codeContextVectorIndex |
context.vector_embedding |
512 | cosine | 16 | 64 |
出力 2: Webhook — 成功
POST {WEBHOOK_BASE_URL}
Content-Type: application/json
X-API-Key: {WEBHOOK_API_KEY}
{
"type": "code-import",
"recordId": "660e8400-e29b-41d4-a716-446655440001",
"projectId": 42,
"organizationId": 1,
"status": "success",
"result": {
"keywords": ["submit", "checkout", "transaction", "action", "primary"],
"embeddingDims": 512
}
}
| フィールド | 備考 |
|---|---|
type |
常に "code-import" |
recordId |
code_id のエコー(UUID 文字列)— 未解決事項 |
projectId |
project_id のエコー |
organizationId |
organization_id のエコー |
result.keywords |
semantics.metadata.words と同一 |
result.embeddingDims |
常に 512 |
出力 3: Webhook — 失敗
POST {WEBHOOK_BASE_URL}
Content-Type: application/json
X-API-Key: {WEBHOOK_API_KEY}
{
"type": "code-import",
"recordId": "660e8400-e29b-41d4-a716-446655440001",
"projectId": 42,
"organizationId": 1,
"status": "failed"
}
失敗時は result なし。例外本文は Webhook に含めない(CloudWatch に送る)。
失敗 Webhook は 再送出の前 に送る。
エラーハンドリング
code と variation の import は、一時的な database transaction エラーを指数バックオフと jitter 付きで最大 8 回試行する。毎回新しい session を使い、evidence 書き込みと index 無効化の原子性を維持する。この retry では AI 呼び出しを繰り返さない。永続エラーは直ちに失敗し、再試行上限後は SQS と DLQ に委ねる。Webhook delivery failure も retry 対象の record failure。
| シナリオ | Webhook(code_id が分かる場合) |
ワーカー側 |
|---|---|---|
エンベロープ不正 / Records なし |
❌ | ValueError 等 |
| JSON パース不可 | ❌ | JSONDecodeError |
| Pydantic 検証 | ベストエフォート failed |
ValidationError |
| preview reference 不正 | failed |
record failure |
セマンティック AgentRunError |
failed |
record failure |
| 埋め込み API エラー | failed |
再送出 |
| DocumentDB 書き込みエラー | failed |
再送出 |
| Webhook HTTP エラー | WARN ログ | SQS retry のため record failure |
handler は全 record を処理して SQS batchItemFailures を返す。1 record の失敗で同じ batch の後続 record は停止しない。event source mapping では ReportBatchItemFailures が必須。
冪等性
- scoped
_idreplace — evidence 変更時のみ document replace と current index invalidation を原子的に行う。 - RDB への書き込みなし — 少なくとも 1 回の Webhook で
successが重複し得る。バックエンドは(type, recordId)の重複投稿に耐性を持つ。 - fingerprint short circuit — 同一 evidence は既存 vector/keyword を再利用し、preview metadata のみ必要に応じ patch する。
ロックされたパラメータ
| パラメータ | 値 / 規則 | 参照 |
|---|---|---|
| セマンティック単語数 | 5〜10 個 | コード解析の構造化出力 |
| 埋め込み次元 | 512 | HNSW + Webhook embeddingDims |
| 埋め込み API 呼び出し | 1 回、入力 2 つ | semantic identity と deterministic context |
| Webhook での識別子 | "type": "code-import" |
ai-status ルーティング |
| HTTP クライアントの Webhook リトライ | timeout=10s、retries=2、指数バックオフ |
仕様 §2 |
ロギング(推奨)
| イベント | レベル | タイミング |
|---|---|---|
code_import.received |
INFO | process_record 開始 |
code_import.parsed |
INFO | Pydantic 検証後 |
code_import.semantic.done |
INFO | コード解析エージェント後 |
code_import.embeddings.done |
INFO | configured provider embedding 後 |
code_import.documentdb.upserted |
INFO | transaction replace/index invalidation 後 |
code_import.webhook.sent |
INFO | HTTP 2xx 後 |
code_import.failed |
ERROR | 終端失敗 |
code_import.webhook.failed |
WARN | Webhook が失敗し、SQS retry 対象 |
extra に載せるとよい値: code_id、project_id、organization_id、message_id。
未解決事項: recordId の型
解決済み。PostgreSQL code.id、worker code_id、webhook recordId は同じ UUID v4 string で、backend schema も受理する。
未解決事項: ソースサイズ上限
仕様書 §11 の「source_code は推奨 200 KB 以下」— Pydantic で同じ上限を強制するか、バックエンドと合意のうえ共通上限を見直す。
フィールド参照(ルックアップ表)
| フィールド | SQS 入力 | DocumentDB 出力 | Webhook 出力 |
|---|---|---|---|
code_id |
✓ | _id |
recordId |
organization_id |
✓ | ✓ | organizationId |
project_id |
✓ | ✓ | projectId |
name / type / based_on |
✓ | ✓ | — |
source_code / css_code |
✓ | ✓ | — |
img_url |
✓ | visual.metadata.image_url* |
— |
component_level |
✓ | context.metadata.component_level |
— |
derived family / variant |
— | context.metadata.* |
— |
semantic_words(エージェント) |
— | semantics.metadata.words |
result.keywords |
| source parser output | — | context.metadata.* |
— |
semantics.vector_embedding |
— | ✓ | — |
context.vector_embedding |
— | ✓ | — |
| stable fingerprint | — | processing.hash |
— |
status |
— | — | success / failed |
*field は常に存在し、preview reference がない場合は null。