Files
foundry-core/internal/platform/canvas_ai_images.go
T
codex-bot d6ee8942f1
Foundry Go checks / check (push) Successful in 2m40s
Foundry Go checks / check (pull_request) Successful in 2m36s
Implement Canvas V2 subgraphs, assets and asynchronous AI execution
2026-11-06 18:36:00 +08:00

52 lines
1.9 KiB
Go

package platform
import (
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"errors"
"gitea.entroia.com/Zayden-Jung/foundry-core/internal/codex"
)
func (s *service) persistCanvasImage(ctx context.Context, tx *sql.Tx, run canvasQueueRun, outputID string, image *codex.CanvasImage) (response, error) {
if image == nil || len(image.Data) == 0 || len(image.Data) > assetLimit {
return nil, errors.New("invalid_image_output")
}
mime, width, height, err := inspectAsset(image.Data)
if err != nil || mime != image.MIME {
return nil, errors.New("invalid_image_output")
}
digest := sha256.Sum256(image.Data)
var id string
err = tx.QueryRowContext(ctx, `INSERT INTO canvas_assets(project,workspace_id,uploaded_by,mime_type,bytes,width,height,digest,idempotency_key) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING id::text`, run.Project, run.Workspace, run.Account, mime, image.Data, width, height, hex.EncodeToString(digest[:]), outputID).Scan(&id)
if err != nil {
return nil, err
}
// Conflict outputs remain readable under the run's originating material even
// before explicit application. No transient or worker-local URL is persisted.
_, err = tx.ExecContext(ctx, `INSERT INTO canvas_asset_bindings(project,workspace_id,asset_id,board_id) VALUES($1,$2,$3,$4)`, run.Project, run.Workspace, id, run.Board)
if err != nil {
return nil, err
}
return response{"output_id": outputID, "kind": "image", "assetId": id, "src": s.assetURL(run.Project, run.Workspace, id), "mime_type": mime, "bytes": len(image.Data), "width": width, "height": height}, nil
}
func canvasModelSupports(model codex.CanvasModel, modality string) bool {
for _, value := range model.OutputModalities {
if value == modality {
return true
}
}
return false
}
func canvasModelAccepts(model codex.CanvasModel, modality string) bool {
for _, value := range model.InputModalities {
if value == modality {
return true
}
}
return false
}