| 92 | } |
| 93 | |
| 94 | func (p QDev) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]interface{}) (interface{}, errors.Error) { |
| 95 | var op tasks.QDevOptions |
| 96 | if err := helper.Decode(options, &op, nil); err != nil { |
| 97 | return nil, err |
| 98 | } |
| 99 | |
| 100 | connectionHelper := helper.NewConnectionHelper( |
| 101 | taskCtx, |
| 102 | nil, |
| 103 | p.Name(), |
| 104 | ) |
| 105 | connection := &models.QDevConnection{} |
| 106 | err := connectionHelper.FirstById(connection, op.ConnectionId) |
| 107 | if err != nil { |
| 108 | return nil, err |
| 109 | } |
| 110 | |
| 111 | // Create S3 client |
| 112 | s3Client, err := tasks.NewQDevS3Client(taskCtx, connection) |
| 113 | if err != nil { |
| 114 | return nil, err |
| 115 | } |
| 116 | |
| 117 | // Create Identity client (new) |
| 118 | identityClient, identityErr := tasks.NewQDevIdentityClient(connection) |
| 119 | if identityErr != nil { |
| 120 | taskCtx.GetLogger().Warn(identityErr, "Failed to create identity client, proceeding without user name resolution") |
| 121 | identityClient = nil |
| 122 | } |
| 123 | |
| 124 | // Resolve S3 prefixes to scan |
| 125 | var s3Prefixes []string |
| 126 | if op.AccountId != "" { |
| 127 | // New-style scope: construct both report paths using region from connection |
| 128 | region := connection.Region |
| 129 | timePart := fmt.Sprintf("%04d", op.Year) |
| 130 | if op.Month != nil { |
| 131 | timePart = fmt.Sprintf("%04d/%02d", op.Year, *op.Month) |
| 132 | } |
| 133 | // Kiro exports data to two well-known S3 prefixes: |
| 134 | // {basePath}/AWSLogs/{accountId}/KiroLogs/ — user report CSVs |
| 135 | // logging/AWSLogs/{accountId}/KiroLogs/ — interaction logs (JSON.gz) |
| 136 | // When basePath is empty, default to "user-report" for CSV data. |
| 137 | reportBase := op.BasePath |
| 138 | if reportBase == "" { |
| 139 | reportBase = "user-report" |
| 140 | } |
| 141 | csvBase := fmt.Sprintf("%s/AWSLogs/%s/KiroLogs", reportBase, op.AccountId) |
| 142 | logBase := fmt.Sprintf("logging/AWSLogs/%s/KiroLogs", op.AccountId) |
| 143 | s3Prefixes = []string{ |
| 144 | fmt.Sprintf("%s/by_user_analytic/%s/%s", csvBase, region, timePart), |
| 145 | fmt.Sprintf("%s/user_report/%s/%s", csvBase, region, timePart), |
| 146 | fmt.Sprintf("%s/GenerateAssistantResponse/%s/%s", logBase, region, timePart), |
| 147 | fmt.Sprintf("%s/GenerateCompletions/%s/%s", logBase, region, timePart), |
| 148 | } |
| 149 | } else { |
| 150 | // Legacy scope: use S3Prefix directly |
| 151 | s3Prefixes = []string{op.S3Prefix} |